当我的react-native应用程序启动时,我无法初始化我的redux-state。我需要在应用程序启动之前进行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;
我已阅读并尝试了不同的策略: - 在随后的api调用回调中包装render方法的return语句 - 在componentWillMount或componentDidMount
中进行调用这些都不适合我。当react-native应用程序启动时,从API调用传递createStore初始状态的标准方法是什么。
答案 0 :(得分:1)
在API调用返回之前,您不能(也不应该)延迟组件的安装(可能甚至会失败)。
您可以在等待API调用返回时显示加载屏幕,方法是检查某个Redux状态(将由API结果填充)在组件中是否仍为空(条件呈现)。
如果要将整个Redux状态替换为API结果,则需要编写根减速器,请参阅答案here。
要在应用启动时启动API调用并在成功时填充状态,您可以将以下内容添加到定义/导入Redux store
的任何位置:
fetch(...).then(result => store.dispatch(...))
您可以查看persisting it with the client是否适合您的用例,而不是从服务器填充Redux状态。
答案 1 :(得分: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))
});
RenderFullPage:
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,否则您更喜欢。
答案 2 :(得分:0)
我会通过在状态中设置加载值然后在ComponentDidMount()
中请求数据来解决此问题。加载后,将this.state.loaded
设置为true
,并使用API返回的数据呈现商店。没有必要这样做,但它会为客户端提供良好的用户体验,并防止不必要地重新呈现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;
我希望这会有所帮助。