当反应原生应用程序启动时,将初始状态从 API 调用传递给 createStore
Posted
技术标签:
【中文标题】当反应原生应用程序启动时,将初始状态从 API 调用传递给 createStore【英文标题】:Passing initial state from API call to createStore when react native application boots up 【发布时间】:2018-10-23 05:56:07 【问题描述】:当我的 react-native 应用程序启动时,我无法初始化我的 redux 状态。我需要在应用程序启动之前进行 api 调用以检索数据以补充我的状态。我想将此调用的结果传递给我的 Provider JSX 元素中的 createStore 函数。 我已经阅读了有关如何执行此操作的不同内容,但它们似乎都不起作用。
这是我的根 App 组件:
import React, Component from 'react';
import View from 'react-native';
import Provider from 'react-redux';
import createStore, applyMiddleware from 'redux';
import ReduxThunk from 'redux-thunk';
import reducers from './reducers';
import RouterComponent from './Router';
class App extends Component
render()
return (
<Provider store=createStore(reducers, , applyMiddleware(ReduxThunk))>
<View style= flex: 1 >
<RouterComponent />
</View>
</Provider>
);
export default App;
我已经阅读并尝试了不同的策略: - 将render方法的return语句包装在api调用的then回调中 - 在 componentWillMount 或 componentDidMount 中调用
这些都不适合我。当 react-native 应用程序启动时,从 API 调用传递 createStore 初始状态的标准方法是什么。
【问题讨论】:
当您拨打componentDidMount
时会发生什么?
【参考方案1】:
最好使用server-rendering
。
counterApp.js
export const counterApp = (state = , action) =>
switch (action.type)
default:
return state;
server.js
//this route will get called for initial page load or page refresh.
server.get('/', (req, res) =>
const counter = parseInt(20, 10) || 0
// demo state,It can be function calling database operation or API.
let preloadedState = counter ;
const store = createStore(counterApp, preloadedState);
const html = renderToString(
<Provider store=store>
<App />
</Provider>
);
const finalState = store.getState()
res.send(renderFullPage(html, finalState))
);
渲染全页:
function renderFullPage(html, preloadedState)
return `
<!doctype html>
<html>
<head>
<title>Redux Universal Example</title>
</head>
<body>
<div id="root">$html</div>
<script>
// WARNING: See the following for security issues around embedding JSON in HTML:
// http://redux.js.org/recipes/ServerRendering.html#security-considerations
window.__PRELOADED_STATE__ = $JSON.stringify(preloadedState).replace(/</g, '\\u003c')
</script>
<script src="/static/bundle.js"></script>
</body>
</html>
`
在 App.js 中,(将仅在客户端呈现。)
在 App.js 中,您可以使用window.__APP_INITIAL_STATE__
访问初始状态,
render(<App ...window.__APP_INITIAL_STATE__ />, document.getElementById('root'));
对于服务器端渲染,你必须设置 webpack 或者你喜欢的。
【讨论】:
这个响应没有考虑服务器没有用 javascript 实现的情况,因此不能使用 React s-s-r。【参考方案2】:您不能(也不应该)延迟组件的安装,直到 API 调用返回(它甚至可能失败)。
您可以在等待 API 调用返回时显示加载屏幕,方法是检查组件中的某个 Redux 状态(将由 API 结果填充)是否仍然为空(条件渲染)。
如果你想用你的API结果替换整个Redux状态,你需要写一个root reducer,见答案here。
要在应用启动时发起 API 调用并在应用成功时填充状态,您可以将以下内容添加到定义/导入 Redux store
的任何位置:
fetch(...).then(result => store.dispatch(...))
如果它适合您的用例,您可以查看persisting it with the client,而不是从服务器填充 Redux 状态。
【讨论】:
【参考方案3】:我会通过在状态中设置一个加载值然后在ComponentDidMount()
中请求数据来解决这个问题。加载后,将 this.state.loaded
设置为 true
并使用从 API 返回的数据呈现存储。没有必要这样做,但它会为客户端提供良好的 UX,并防止不必要地重新渲染 RouterComponent
两次。
无论您是否决定设置error
和loaded
值,这里的想法是在ComponentDidMount
方法中获取数据并使用新数据更新App.state
- 这将导致组件重新- 渲染并将您的数据应用到新的Store
。
import React, Component from 'react';
import View from 'react-native';
import Provider from 'react-redux';
import createStore, applyMiddleware from 'redux';
import ReduxThunk from 'redux-thunk';
import reducers from './reducers';
import RouterComponent from './Router';
class App extends Component
constructor(props)
super(props);
this.state =
initialState: ,
loaded: false,
error: false
componentDidMount()
// Perform your API call, using which ever library or method you choose, i prefer axios so will demonstrate with this:
axios.get('path/to/api')
.then(res =>
// Send the response to state, which will cause the component to re-render and create the store with the new initialState
this.setState(
initialState: res.data,
loaded: true
);
)
.catch(err =>
console.error('Error initiating application. Failed to retrieve data from API')
this.setState(error: true);
);
render()
// This would be completely optional, but I would show some form of loading icon or text whilst you wait for the API to fetch the data.
if(!this.state.loaded)
return "Loading";
// If there was an error getting the data, tell the client
else if(this.state.error)
return "Error loading data from API. Please reload the application or try again.";
// If all is well, the component should render the store with the correct initialState
else
return (
<Provider store=createStore(reducers, this.state.initialState, applyMiddleware(ReduxThunk))>
<View style= flex: 1 >
<RouterComponent />
</View>
</Provider>
);
export default App;
我希望这会有所帮助。
【讨论】:
以上是关于当反应原生应用程序启动时,将初始状态从 API 调用传递给 createStore的主要内容,如果未能解决你的问题,请参考以下文章