Reactjs React/Redux-应用程序加载/init时的调度操作
我有来自服务器的令牌身份验证,所以当我的Redux应用程序最初加载时,我需要向该服务器发出请求,以检查用户是否经过身份验证,如果是,我应该获得令牌Reactjs React/Redux-应用程序加载/init时的调度操作,reactjs,redux,Reactjs,Redux,我有来自服务器的令牌身份验证,所以当我的Redux应用程序最初加载时,我需要向该服务器发出请求,以检查用户是否经过身份验证,如果是,我应该获得令牌 我发现不建议使用Redux core INIT actions,所以在呈现应用程序之前,如何分派操作?您可以在RootcomponentDidMount方法中分派操作,在render方法中可以验证身份验证状态 大概是这样的: class App extends Component { componentDidMount() { this.
我发现不建议使用Redux core INIT actions,所以在呈现应用程序之前,如何分派操作?您可以在Root
componentDidMount
方法中分派操作,在render
方法中可以验证身份验证状态
大概是这样的:
class App extends Component {
componentDidMount() {
this.props.getAuth()
}
render() {
return this.props.isReady
? <div> ready </div>
: <div>not ready</div>
}
}
const mapStateToProps = (state) => ({
isReady: state.isReady,
})
const mapDispatchToProps = {
getAuth,
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
class Startup extends Component {
static propTypes = {
connection: PropTypes.object
}
componentDidMount() {
this.props.actions.initialiseConnection();
}
render() {
return this.props.connection
? this.props.children
: (<p>Loading...</p>);
}
}
function mapStateToProps(state) {
return {
connection: state.connection
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Startup);
类应用程序扩展组件{
componentDidMount(){
this.props.getAuth()
}
render(){
归还这个。道具。我准备好了
准备好的
:没有准备好
}
}
常量mapStateToProps=(状态)=>({
已经准备好了,
})
const mapDispatchToProps={
getAuth,
}
导出默认连接(mapStateToProps、mapDispatchToProps)(应用程序)
更新2020:
除了其他解决方案外,我还使用Redux中间件检查每个登录尝试失败的请求:
export default () => next => action => {
const result = next(action);
const { type, payload } = result;
if (type.endsWith('Failure')) {
if (payload.status === 401) {
removeToken();
window.location.replace('/login');
}
}
return result;
};
更新2018:此答案适用于反应路由器3
我用react路由器道具解决了这个问题。这是代码的样子:
//在应用程序开始呈现react route及其任何相关DOM元素之前,此函数只调用一次
//它可用于向应用程序添加初始配置设置
职能部门(调度){
返回(下一个状态、替换、回调)=>{
分派(performTokenRequest())
.然后(()=>{
//回调就像一个“下一个”函数,应用程序初始化将停止,直到调用它为止。
回调();
});
};
}
常量应用=()=>(
);
我对为此提出的任何解决方案都不满意,然后我想到我正在考虑需要呈现的类。如果我刚刚创建了一个用于启动的类,然后将其推入componentDidMount
方法,然后让render
显示一个加载屏幕,会怎么样
<Provider store={store}>
<Startup>
<Router>
<Switch>
<Route exact path='/' component={Homepage} />
</Switch>
</Router>
</Startup>
</Provider>
然后是这样的:
class App extends Component {
componentDidMount() {
this.props.getAuth()
}
render() {
return this.props.isReady
? <div> ready </div>
: <div>not ready</div>
}
}
const mapStateToProps = (state) => ({
isReady: state.isReady,
})
const mapDispatchToProps = {
getAuth,
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
class Startup extends Component {
static propTypes = {
connection: PropTypes.object
}
componentDidMount() {
this.props.actions.initialiseConnection();
}
render() {
return this.props.connection
? this.props.children
: (<p>Loading...</p>);
}
}
function mapStateToProps(state) {
return {
connection: state.connection
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Startup);
类启动扩展组件{
静态类型={
连接:PropTypes.object
}
componentDidMount(){
this.props.actions.initialiseConnection();
}
render(){
返回此.props.connection
这是我的道具
:(加载…);
}
}
函数MapStateTops(状态){
返回{
连接:state.connection
};
}
功能图DispatchToprops(调度){
返回{
操作:bindActionCreators(操作、调度)
};
}
导出默认连接(
MapStateTops,
mapDispatchToProps
)(启动);
然后编写一些redux操作来异步初始化应用程序。使用:Apollo客户端2.0、React路由器v4、React 16(光纤) 所选答案使用旧路由器v3。我需要执行“分派”以加载应用程序的全局设置。诀窍是使用componentWillUpdate,尽管示例使用apollo客户端,但不获取解决方案是等效的。 你不需要一束水 SettingsLoad.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from "redux";
import {
graphql,
compose,
} from 'react-apollo';
import {appSettingsLoad} from './actions/appActions';
import defQls from './defQls';
import {resolvePathObj} from "./utils/helper";
class SettingsLoad extends Component {
constructor(props) {
super(props);
}
componentWillMount() { // this give infinite loop or no sense if componente will mount or not, because render is called a lot of times
}
//componentWillReceiveProps(newProps) { // this give infinite loop
componentWillUpdate(newProps) {
const newrecord = resolvePathObj(newProps, 'getOrgSettings.getOrgSettings.record');
const oldrecord = resolvePathObj(this.props, 'getOrgSettings.getOrgSettings.record');
if (newrecord === oldrecord) {
// when oldrecord (undefined) !== newrecord (string), means ql is loaded, and this will happens
// one time, rest of time:
// oldrecord (undefined) == newrecord (undefined) // nothing loaded
// oldrecord (string) == newrecord (string) // ql loaded and present in props
return false;
}
if (typeof newrecord ==='undefined') {
return false;
}
// here will executed one time
setTimeout(() => {
this.props.appSettingsLoad( JSON.parse(this.props.getOrgSettings.getOrgSettings.record));
}, 1000);
}
componentDidMount() {
//console.log('did mount this props', this.props);
}
render() {
const record = resolvePathObj(this.props, 'getOrgSettings.getOrgSettings.record');
return record
? this.props.children
: (<p>...</p>);
}
}
const withGraphql = compose(
graphql(defQls.loadTable, {
name: 'loadTable',
options: props => {
const optionsValues = { };
optionsValues.fetchPolicy = 'network-only';
return optionsValues ;
},
}),
)(SettingsLoad);
const mapStateToProps = (state, ownProps) => {
return {
myState: state,
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators ({appSettingsLoad, dispatch }, dispatch ); // to set this.props.dispatch
};
const ComponentFull = connect(
mapStateToProps ,
mapDispatchToProps,
)(withGraphql);
export default ComponentFull;
import React,{Component}来自'React';
从'react redux'导入{connect};
从“redux”导入{bindActionCreators};
进口{
graphql,
组成
}从‘阿波罗反应’;
从“/actions/appActions”导入{appSettingsLoad};
从“/defQls”导入defQls;
从“/utils/helper”导入{ResolvePathBJ}”;
类设置加载扩展组件{
建造师(道具){
超级(道具);
}
componentWillMount(){//这会给出无限循环,或者说对于Component是否装载没有意义,因为render被调用了很多次
}
//componentWillReceiveProps(newProps){//这将给出无限循环
组件将更新(newProps){
const newrecord=resolvephobj(newProps'getOrgSettings.getOrgSettings.record');
const oldrecord=ResolvePathBj(this.props,'getOrgSettings.getOrgSettings.record');
if(newrecord==oldrecord){
//当oldrecord(未定义)!==newrecord(字符串)时,表示加载了ql,这将发生
//一次,其余时间:
//oldrecord(未定义)=newrecord(未定义)//未加载任何内容
//oldrecord(string)=newrecord(string)//ql加载并显示在道具中
返回false;
}
if(typeof newrecord==='undefined'){
返回false;
}
//这里将执行一次
设置超时(()=>{
appsetingsload(JSON.parse(this.props.getOrgSettings.getOrgSettings.record));
}, 1000);
}
componentDidMount(){
//console.log('did mount this props',this.props);
}
render(){
const record=ResolvePathBJ(this.props,'getOrgSettings.getOrgSettings.record');
返回记录
这是我的道具
:(…);
}
}
常量withGraphql=compose(
graphql(defQls.loadTable{
名称:'loadTable',
选项:道具=>{
const optionsValues={};
optionsValues.fetchPolicy='仅限网络';
返回选项值;
},
}),
)(设置SLOAD);
const mapStateToProps=(state,ownProps)=>{
返回{
我的国家:国家,
};
};
const mapDispatchToProps=(调度)=>{
返回bindActionCreators({appSettingsLoad,dispatch},dispatch);//设置this.props.dispatch
};
const ComponentFull=connect(
MapStateTops,
mapDispatchToProps,
)(使用GraphQL);
导出默认组件full;
App.js
class App extends Component<Props> {
render() {
return (
<ApolloProvider client={client}>
<Provider store={store} >
<SettingsLoad>
<BrowserRouter>
<Switch>
<LayoutContainer
t={t}
i18n={i18n}
path="/myaccount"
component={MyAccount}
title="form.myAccount"
/>
<LayoutContainer
t={t}
i18n={i18n}
path="/dashboard"
component={Dashboard}
title="menu.dashboard"
/>
类应用程序扩展组件{
render(){
返回(
这里的所有答案似乎都是关于创建根组件并在componentDidMount中启动它的变体。关于redux,我最喜欢的一件事是它将从组件生命周期中提取数据解耦。我看不出有什么原因
import { fork, all } from 'redux-saga/effects';
import launchSaga from './launchSaga';
// ... other saga imports
// Single entry point to start all sagas at once
const root = function* rootSaga() {
yield all([
fork( ... )
// ... other sagas
fork(launchSaga)
]);
};
export default root;
useEffect(() => store.dispatch(handleAppInit()), []);
import React, { useEffect } from 'react';
import { Provider } from 'react-redux';
import AppInitActions from './store/actions/appInit';
import store from './store';
export default function App() {
useEffect(() => store.dispatch(AppInitActions.handleAppInit()), []);
return (
<Provider store={store}>
<div>
Hello World
</div>
</Provider>
);
}
import { appPreInit } from '../store/actions';
// app preInit is an action: const appPreInit = () => ({ type: APP_PRE_INIT })
import { useDispatch } from 'react-redux';
export default App() {
const dispatch = useDispatch();
// only change the dispatch effect when dispatch has changed, which should be never
useEffect(() => dispatch(appPreInit()), [ dispatch ]);
return (<div>---your app here---</div>);
}
class SwitchAccount extends Component {
constructor(props) {
super(props);
this.Format_Account_List = this.Format_Account_List.bind(this); //function to format list for html form drop down
//Local state
this.state = {
formattedUserAccounts : [], //Accounts list with html formatting for drop down
selectedUserAccount: [] //selected account by user
}
}
//Check if accounts has been updated by redux thunk and update state
componentDidUpdate(prevProps) {
if (prevProps.accounts !== this.props.accounts) {
this.Format_Account_List(this.props.accounts);
}
}
//take the JSON data and work with it :-)
Format_Account_List(json_data){
let a_users_list = []; //create user array
for(let i = 0; i < json_data.length; i++) {
let data = JSON.parse(json_data[i]);
let s_username = <option key={i} value={data.s_username}>{data.s_username}</option>;
a_users_list.push(s_username); //object
}
this.setState({formattedUserAccounts: a_users_list}); //state for drop down list (html formatted)
}
changeAccount() {
//do some account change checks here
}
render() {
return (
<Form >
<Form.Group >
<Form.Control onChange={e => this.setState( {selectedUserAccount : e.target.value})} as="select">
{this.state.formattedUserAccounts}
</Form.Control>
</Form.Group>
<Button variant="info" size="lg" onClick={this.changeAccount} block>Select</Button>
</Form>
);
}
}
const mapStateToProps = state => ({
accounts: state.accountSelection.accounts, //accounts from redux store
});
export default connect(mapStateToProps)(SwitchAccount);
React.useEffect(props.dispatchOnAuthListener, []);
function App(props) {
const [user, setUser] = React.useState(props.authUser);
React.useEffect(() => setUser(props.authUser), [props.authUser]);
React.useEffect(props.dispatchOnAuthListener, []);
return <>{user.loading ? "Loading.." :"Hello! User"}<>;
}
const mapStateToProps = (state) => {
return {
authUser: state.authentication,
};
};
const mapDispatchToProps = (dispatch) => {
return {
dispatchOnAuthListener: () => dispatch(registerOnAuthListener()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);