mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f233dc3b6 | ||
|
|
5b34ccb0fc | ||
|
|
3f1db67495 | ||
|
|
78eec74770 | ||
|
|
843ef1a5da | ||
|
|
926d6f3704 | ||
|
|
8b320a51a9 | ||
|
|
1e1d34a236 | ||
|
|
e195f5e751 | ||
|
|
e0f4fd5de6 | ||
|
|
fd8e6d3eaa |
@@ -15,12 +15,12 @@ const infoLog = require('infoLog');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
type SimpleTask = {
|
||||
name: string;
|
||||
run: () => void;
|
||||
name: string,
|
||||
run: () => void,
|
||||
};
|
||||
type PromiseTask = {
|
||||
name: string;
|
||||
gen: () => Promise<any>;
|
||||
name: string,
|
||||
gen: () => Promise<any>,
|
||||
};
|
||||
export type Task = Function | SimpleTask | PromiseTask;
|
||||
|
||||
@@ -75,7 +75,7 @@ class TaskQueue {
|
||||
...queue,
|
||||
tasks: queue.tasks.filter((task) => tasksToCancel.indexOf(task) === -1),
|
||||
}))
|
||||
.filter((queue) => queue.tasks.length > 0);
|
||||
.filter((queue, idx) => (queue.tasks.length > 0 || idx === 0));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +151,10 @@ class TaskQueue {
|
||||
DEBUG && infoLog('exec gen task ' + task.name);
|
||||
task.gen()
|
||||
.then(() => {
|
||||
DEBUG && infoLog('onThen for gen task ' + task.name, {stackIdx, queueStackSize: this._queueStack.length});
|
||||
DEBUG && infoLog(
|
||||
'onThen for gen task ' + task.name,
|
||||
{stackIdx, queueStackSize: this._queueStack.length},
|
||||
);
|
||||
this._queueStack[stackIdx].popable = true;
|
||||
this.hasTasksToProcess() && this._onMoreTasks();
|
||||
})
|
||||
|
||||
@@ -142,4 +142,13 @@ describe('TaskQueue', () => {
|
||||
expectToBeCalledOnce(task4);
|
||||
expect(taskQueue.hasTasksToProcess()).toBe(false);
|
||||
});
|
||||
|
||||
it('should not crash when last task is cancelled', () => {
|
||||
const task1 = jest.fn();
|
||||
taskQueue.enqueue(task1);
|
||||
taskQueue.cancelTasks([task1]);
|
||||
clearTaskQueue(taskQueue);
|
||||
expect(task1).not.toBeCalled();
|
||||
expect(taskQueue.hasTasksToProcess()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -125,9 +125,6 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
|
||||
progress,
|
||||
} = nextState;
|
||||
|
||||
// update scenes.
|
||||
this.setState(nextState);
|
||||
|
||||
// get the transition spec.
|
||||
const transitionUserSpec = nextProps.configureTransition ?
|
||||
nextProps.configureTransition(
|
||||
@@ -168,12 +165,14 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
// play the transition.
|
||||
nextProps.onTransitionStart && nextProps.onTransitionStart(
|
||||
this._transitionProps,
|
||||
this._prevTransitionProps,
|
||||
);
|
||||
Animated.parallel(animations).start(this._onTransitionEnd);
|
||||
// update scenes and play the transition
|
||||
this.setState(nextState, () => {
|
||||
nextProps.onTransitionStart && nextProps.onTransitionStart(
|
||||
this._transitionProps,
|
||||
this._prevTransitionProps,
|
||||
);
|
||||
Animated.parallel(animations).start(this._onTransitionEnd);
|
||||
});
|
||||
}
|
||||
|
||||
render(): ReactElement<any> {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React"
|
||||
s.version = package['version']
|
||||
s.version = "0.30.0"
|
||||
s.summary = package['description']
|
||||
s.description = <<-DESC
|
||||
React Native apps are built using the React JS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=1000.0.0-master
|
||||
VERSION_NAME=0.30.0
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
@@ -91,9 +93,10 @@ public class StackTraceHelper {
|
||||
* Convert a JavaScript stack trace (see {@code parseErrorStack} JS module) to an array of
|
||||
* {@link StackFrame}s.
|
||||
*/
|
||||
public static StackFrame[] convertJsStackTrace(ReadableArray stack) {
|
||||
StackFrame[] result = new StackFrame[stack.size()];
|
||||
for (int i = 0; i < stack.size(); i++) {
|
||||
public static StackFrame[] convertJsStackTrace(@Nullable ReadableArray stack) {
|
||||
int size = stack != null ? stack.size() : 0;
|
||||
StackFrame[] result = new StackFrame[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
ReadableMap frame = stack.getMap(i);
|
||||
String methodName = frame.getString("methodName");
|
||||
String fileName = frame.getString("file");
|
||||
|
||||
@@ -68,25 +68,6 @@ static JSValueRef nativeInjectHMRUpdate(
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception);
|
||||
|
||||
static std::string executeJSCallWithJSC(
|
||||
JSGlobalContextRef ctx,
|
||||
const std::string& methodName,
|
||||
const std::vector<folly::dynamic>& arguments) {
|
||||
#ifdef WITH_FBSYSTRACE
|
||||
FbSystraceSection s(
|
||||
TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.executeJSCall",
|
||||
"method", methodName);
|
||||
#endif
|
||||
|
||||
// Evaluate script with JSC
|
||||
folly::dynamic jsonArgs(arguments.begin(), arguments.end());
|
||||
auto js = folly::to<std::string>(
|
||||
"__fbBatchedBridge.", methodName, ".apply(null, ",
|
||||
folly::toJson(jsonArgs), ")");
|
||||
auto result = evaluateScript(ctx, String(js.c_str()), nullptr);
|
||||
return Value(ctx, result).toJSONString();
|
||||
}
|
||||
|
||||
std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(Bridge *bridge) {
|
||||
return std::unique_ptr<JSExecutor>(new JSCExecutor(bridge, cacheDir_, m_jscConfig));
|
||||
}
|
||||
@@ -202,6 +183,8 @@ void JSCExecutor::terminateOnJSVMThread() {
|
||||
|
||||
m_batchedBridge.reset();
|
||||
m_flushedQueueObj.reset();
|
||||
m_callFunctionObj.reset();
|
||||
m_invokeCallbackObj.reset();
|
||||
|
||||
s_globalContextRefToJSCExecutor.erase(m_context);
|
||||
JSGlobalContextRelease(m_context);
|
||||
@@ -266,6 +249,8 @@ bool JSCExecutor::ensureBatchedBridgeObject() {
|
||||
}
|
||||
m_batchedBridge = folly::make_unique<Object>(batchedBridgeValue.asObject());
|
||||
m_flushedQueueObj = folly::make_unique<Object>(m_batchedBridge->getProperty("flushedQueue").asObject());
|
||||
m_callFunctionObj = folly::make_unique<Object>(m_batchedBridge->getProperty("callFunctionReturnFlushedQueue").asObject());
|
||||
m_invokeCallbackObj = folly::make_unique<Object>(m_batchedBridge->getProperty("invokeCallbackAndReturnFlushedQueue").asObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -290,6 +275,10 @@ void JSCExecutor::flush() {
|
||||
}
|
||||
|
||||
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
|
||||
#ifdef WITH_FBSYSTRACE
|
||||
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.callFunction");
|
||||
#endif
|
||||
|
||||
if (!ensureBatchedBridgeObject()) {
|
||||
throwJSExecutionException(
|
||||
"Couldn't call JS module %s, method %s: bridge configuration isn't available. This "
|
||||
@@ -298,27 +287,35 @@ void JSCExecutor::callFunction(const std::string& moduleId, const std::string& m
|
||||
methodId.c_str());
|
||||
}
|
||||
|
||||
std::vector<folly::dynamic> call {
|
||||
moduleId,
|
||||
methodId,
|
||||
std::move(arguments),
|
||||
String argsString = String(folly::toJson(std::move(arguments)).c_str());
|
||||
String moduleIdStr(moduleId.c_str());
|
||||
String methodIdStr(methodId.c_str());
|
||||
JSValueRef args[] = {
|
||||
JSValueMakeString(m_context, moduleIdStr),
|
||||
JSValueMakeString(m_context, methodIdStr),
|
||||
Value::fromJSON(m_context, argsString)
|
||||
};
|
||||
std::string calls = executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
|
||||
m_bridge->callNativeModules(*this, calls, true);
|
||||
auto result = m_callFunctionObj->callAsFunction(3, args);
|
||||
m_bridge->callNativeModules(*this, result.toJSONString(), true);
|
||||
}
|
||||
|
||||
void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
|
||||
#ifdef WITH_FBSYSTRACE
|
||||
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.invokeCallback");
|
||||
#endif
|
||||
|
||||
if (!ensureBatchedBridgeObject()) {
|
||||
throwJSExecutionException(
|
||||
"Couldn't invoke JS callback %d: bridge configuration isn't available. This shouldn't be possible. Congratulations.", (int) callbackId);
|
||||
}
|
||||
|
||||
std::vector<folly::dynamic> call {
|
||||
(double) callbackId,
|
||||
std::move(arguments)
|
||||
String argsString = String(folly::toJson(std::move(arguments)).c_str());
|
||||
JSValueRef args[] = {
|
||||
JSValueMakeNumber(m_context, callbackId),
|
||||
Value::fromJSON(m_context, argsString)
|
||||
};
|
||||
std::string calls = executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
|
||||
m_bridge->callNativeModules(*this, calls, true);
|
||||
auto result = m_invokeCallbackObj->callAsFunction(2, args);
|
||||
m_bridge->callNativeModules(*this, result.toJSONString(), true);
|
||||
}
|
||||
|
||||
void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
|
||||
|
||||
@@ -91,6 +91,8 @@ private:
|
||||
folly::dynamic m_jscConfig;
|
||||
std::unique_ptr<Object> m_batchedBridge;
|
||||
std::unique_ptr<Object> m_flushedQueueObj;
|
||||
std::unique_ptr<Object> m_callFunctionObj;
|
||||
std::unique_ptr<Object> m_invokeCallbackObj;
|
||||
|
||||
/**
|
||||
* WebWorker constructor. Must be invoked from thread this Executor will run on.
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ title: Networking
|
||||
layout: docs
|
||||
category: The Basics
|
||||
permalink: docs/network.html
|
||||
next: navigators
|
||||
next: using-navigators
|
||||
---
|
||||
|
||||
Many mobile apps need to load resources from a remote URL. You may want to make a POST request to a REST API, or you may simply need to fetch a chunk of static content from another server.
|
||||
|
||||
@@ -13,9 +13,7 @@ Running an iOS app on a device requires an [Apple Developer account](https://dev
|
||||
|
||||
You can iterate quickly on device using the development server. First, ensure that you are on the same Wi-Fi network as your computer.
|
||||
|
||||
1. Open `ios/YourApp/AppDelegate.m`
|
||||
2. Change the host in the URL from `localhost` to your laptop's IP address. On Mac, you can find the IP address in System Preferences / Network.
|
||||
3. In Xcode, select your phone as build target and press "Build and run"
|
||||
In Xcode, select your phone as build target and press "Build and run"
|
||||
|
||||
> Hint
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
id: navigators
|
||||
id: using-navigators
|
||||
title: Using Navigators
|
||||
layout: docs
|
||||
category: The Basics
|
||||
@@ -33,9 +33,9 @@ exports.projectConfig = function projectConfigAndroid(folder, userConfig) {
|
||||
const packageFolder = userConfig.packageFolder ||
|
||||
packageName.replace(/\./g, path.sep);
|
||||
|
||||
const mainActivityPath = path.join(
|
||||
const mainFilePath = path.join(
|
||||
sourceDir,
|
||||
userConfig.mainActivityPath || `src/main/java/${packageFolder}/MainActivity.java`
|
||||
userConfig.mainFilePath || `src/main/java/${packageFolder}/MainApplication.java`
|
||||
);
|
||||
|
||||
const stringsPath = path.join(
|
||||
@@ -68,7 +68,7 @@ exports.projectConfig = function projectConfigAndroid(folder, userConfig) {
|
||||
buildGradlePath,
|
||||
settingsGradlePath,
|
||||
assetsPath,
|
||||
mainActivityPath,
|
||||
mainFilePath,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports = function makeImportPatch(packageImportPath) {
|
||||
return {
|
||||
pattern: 'import com.facebook.react.ReactActivity;',
|
||||
pattern: 'import com.facebook.react.ReactApplication;',
|
||||
patch: '\n' + packageImportPath,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -27,12 +27,12 @@ module.exports = function registerNativeAndroidModule(
|
||||
applyPatch(projectConfig.stringsPath, makeStringsPatch(params, name));
|
||||
|
||||
applyPatch(
|
||||
projectConfig.mainActivityPath,
|
||||
projectConfig.mainFilePath,
|
||||
makePackagePatch(androidConfig.packageInstance, params, name)
|
||||
);
|
||||
|
||||
applyPatch(
|
||||
projectConfig.mainActivityPath,
|
||||
projectConfig.mainFilePath,
|
||||
makeImportPatch(androidConfig.packageImportPath)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -36,12 +36,12 @@ module.exports = function unregisterNativeAndroidModule(
|
||||
revokePatch(projectConfig.stringsPath, makeStringsPatch(params, name));
|
||||
|
||||
revokePatch(
|
||||
projectConfig.mainActivityPath,
|
||||
projectConfig.mainFilePath,
|
||||
makePackagePatch(androidConfig.packageInstance, params, name)
|
||||
);
|
||||
|
||||
revokePatch(
|
||||
projectConfig.mainActivityPath,
|
||||
projectConfig.mainFilePath,
|
||||
makeImportPatch(androidConfig.packageImportPath)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ const makeImportPatch = require('../../../../src/android/patches/0.17/makeImport
|
||||
const applyPatch = require('../../../../src/android/patches/applyPatch');
|
||||
|
||||
const projectConfig = {
|
||||
mainActivityPath: 'MainActivity.java',
|
||||
mainFilePath: 'MainActivity.java',
|
||||
};
|
||||
|
||||
const packageImportPath = 'import some.example.project';
|
||||
|
||||
@@ -7,7 +7,7 @@ const makePackagePatch = require('../../../../src/android/patches/0.17/makePacka
|
||||
const applyPatch = require('../../../../src/android/patches/applyPatch');
|
||||
|
||||
const projectConfig = {
|
||||
mainActivityPath: 'MainActivity.java',
|
||||
mainFilePath: 'MainActivity.java',
|
||||
};
|
||||
|
||||
const packageInstance = 'new SomeLibrary(${foo}, ${bar}, \'something\')';
|
||||
|
||||
@@ -7,7 +7,7 @@ const makeImportPatch = require('../../../../src/android/patches/0.18/makeImport
|
||||
const applyPatch = require('../../../../src/android/patches/applyPatch');
|
||||
|
||||
const projectConfig = {
|
||||
mainActivityPath: 'MainActivity.java',
|
||||
mainFilePath: 'MainActivity.java',
|
||||
};
|
||||
|
||||
const packageImportPath = 'import some.example.project';
|
||||
|
||||
@@ -7,7 +7,7 @@ const makePackagePatch = require('../../../../src/android/patches/0.18/makePacka
|
||||
const applyPatch = require('../../../../src/android/patches/applyPatch');
|
||||
|
||||
const projectConfig = {
|
||||
mainActivityPath: 'MainActivity.java',
|
||||
mainFilePath: 'MainActivity.java',
|
||||
};
|
||||
|
||||
const packageInstance = 'new SomeLibrary(${foo}, ${bar}, \'something\')';
|
||||
|
||||
@@ -7,7 +7,7 @@ const makeImportPatch = require('../../../../src/android/patches/0.20/makeImport
|
||||
const applyPatch = require('../../../../src/android/patches/applyPatch');
|
||||
|
||||
const projectConfig = {
|
||||
mainActivityPath: 'MainActivity.java',
|
||||
mainFilePath: 'MainActivity.java',
|
||||
};
|
||||
|
||||
const packageImportPath = 'import some.example.project';
|
||||
|
||||
@@ -7,7 +7,7 @@ const makePackagePatch = require('../../../../src/android/patches/0.20/makePacka
|
||||
const applyPatch = require('../../../../src/android/patches/applyPatch');
|
||||
|
||||
const projectConfig = {
|
||||
mainActivityPath: 'MainActivity.java',
|
||||
mainFilePath: 'MainActivity.java',
|
||||
};
|
||||
|
||||
const packageInstance = 'new SomeLibrary(${foo}, ${bar}, \'something\')';
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native",
|
||||
"version": "1000.0.0",
|
||||
"version": "0.30.0",
|
||||
"description": "A framework for building native apps using React",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": {
|
||||
@@ -204,4 +204,4 @@
|
||||
"react": "~15.2.0",
|
||||
"shelljs": "0.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -31,7 +31,9 @@ gradle.projectsEvaluated {
|
||||
productFlavors.each { productFlavorName ->
|
||||
buildTypes.each { buildTypeName ->
|
||||
// Create variant and target names
|
||||
def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}"
|
||||
def flavorNameCapitalized = "${productFlavorName.capitalize()}"
|
||||
def buildNameCapitalized = "${buildTypeName.capitalize()}"
|
||||
def targetName = "${flavorNameCapitalized}${buildNameCapitalized}"
|
||||
def targetPath = productFlavorName ?
|
||||
"${productFlavorName}/${buildTypeName}" :
|
||||
"${buildTypeName}"
|
||||
@@ -92,8 +94,8 @@ gradle.projectsEvaluated {
|
||||
currentBundleTask.dependsOn("merge${targetName}Resources")
|
||||
currentBundleTask.dependsOn("merge${targetName}Assets")
|
||||
|
||||
runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
|
||||
runBefore("processX86${targetName}Resources", currentBundleTask)
|
||||
runBefore("process${flavorNameCapitalized}Armeabi-v7a${buildNameCapitalized}Resources", currentBundleTask)
|
||||
runBefore("process${flavorNameCapitalized}X86${buildNameCapitalized}Resources", currentBundleTask)
|
||||
runBefore("processUniversal${targetName}Resources", currentBundleTask)
|
||||
runBefore("process${targetName}Resources", currentBundleTask)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user