【问题标题】:Redux reducer initial state issuesRedux reducer 初始状态问题
【发布时间】:2018-01-19 20:19:14
【问题描述】:

我有一个 reducer 可以设置 redux 表单的状态,也可以设置只显示页面(不是表单)的状态...

import { LOAD_USER_SUCCESS, LOAD_USERS_SUCCESS } from '../actions/types';

const INITIAL_STATE = { data: [] }

export default function (state = INITIAL_STATE, action) {  
  switch(action.type) {
    case LOAD_USER_SUCCESS:
      return { ...state, data: action.data };
    case LOAD_USERS_SUCCESS:
      console.log('LOAD_USER_SUCCESS');
      return { ...state, data: action.data };
    default:
      return state;
  }
}

你可以在上面看到我设置了一个初始状态,我这样做是因为否则只显示页面在获取完成之前抛出错误:

TypeError:无法读取未定义的属性“map”(在下面的“this.props.users”处抛出)...

class Users extends React.Component {

  componentDidMount() {
        this.props.loadUsers();
  }

  render() {

    return (
      <PageWrapper>
          <table className="w-full text-left table-collapse">
            <thead>
              <tr className="text-sm text-grey-darker bg-grey-lightest">
                <TableTH name="Name" />
                <TableTH name="Email" />
              </tr>
            </thead>

            <tbody>
             {this.props.users.map((user, i) => (
                <UserListItem firstName={user.profile.firstName} lastName={user.profile.lastName} email={user.email} key={i} />
              ))}
            </tbody>
          </table>
      </PageWrapper>
    );
  }
}

function TableTH(props) {
    return (
        <th className="p-2">{props.name}</th>
    )
}

function mapStateToProps(state, props) {  
  if(state.user.data) {
    return { users: state.user.data }
  } else {
    return {};
  }
}

export default connect(mapStateToProps, { loadUsers })(Users);  

但 redux-form 填充相同的初始状态(无内容),并且在 fetch 完成时不会更新,因为它是不可变的。

如果我删除 reducer 中的 INITIAL 状态,redux-form 会完美填充,但我会收到上面提到的“map”错误。

这是表格:

let UserForm = props => {

  const { handleSubmit, onSubmit } = props;

    return (
    <form onSubmit={handleSubmit(onSubmit)}>

            <FormItem
                label = { <label htmlFor="firstName">First Name</label> }
                field = { <Field name="firstName" type="text" placeholder="First name" component="input" className="w-full"/>} 
            />

            <FormItem
                label = { <label htmlFor="lastName">Last Name</label> }
                field = { <Field name="lastName" type="text" placeholder="Last name" component="input" className="w-full"/> }
            />

            <FormItem
                label = { <label htmlFor="email">Email</label> }
                field = { <Field name="email" type="text" placeholder="Email" component="input" className="w-full"/>}
            />

            <FormFooter
                left={ <Button href="/users" icon="fa-ban" text="Cancel" /> }
                right={ <button type="submit">Save</button> }
            />

        </form>
    )
}

UserForm = reduxForm({
  form: 'userForm'
})(UserForm)

function mapStateToProps(state) {  
  return { initialValues: state.user.data }
}

UserForm = connect(mapStateToProps
)(UserForm)

export default UserForm

这里是我创建商店的地方:

const store = createStore(
  reducers,
  applyMiddleware(reduxThunk)
);

ReactDOM.render(
  <Provider store={store}>
        <App />
    </Provider>,
  document.getElementById('root')
)

registerServiceWorker();

这是主要的减速器:

import { combineReducers } from 'redux';  
import { reducer as formReducer } from 'redux-form';  
import authReducer from './auth_reducer';
import userReducer from './user_reducer';
import calendarReducer from './calendar_reducer';

const rootReducer = combineReducers({  
  auth: authReducer,
  form: formReducer,
  user: userReducer,
  calendar: calendarReducer
});

export default rootReducer; 

我应该如何改变它以满足两个页面?

【问题讨论】:

  • 请显示您将减速器分配给商店的位置。你用combineReducers吗?检查mapStateToProps 中的状态输出,您将得到问题的答案。
  • @AndrzejDybionka 更新

标签: reactjs redux react-redux redux-form


【解决方案1】:

由于你没有提供完整的代码,我可以给你三个提示:

  1. 您应该将initialValues 作为对象而不是数组传递。所以你的用户reducer的初始状态应该是const INITIAL_STATE = { data: {} }

  2. 你提到了一些关于不可变的事情。我看不到你是如何导入 redux-form 的,但由于你的 Redux 状态不是不可变对象,你不应该从 redux-form/immutable 导入 redux-form,而应该从 redux-form 导入。

  3. rootReducer 没有redux-form reducer。

Reducer 应该如下所示:

import { reducer as formReducer } from 'redux-form';

const rootReducer = combineReducers({  
  auth: authReducer,
  user: userReducer,
  form: formReducer
});

【讨论】:

  • 我试过你上面的#1,但没有帮助。我已经有了 redux-form,我在为这篇文章精简代码时不小心省略了它。我正在使用完整的 reducer 代码更新原始帖子。
【解决方案2】:

解决此问题的一种方法是将INITIAL_STATE 设置为{},然后在您的组件中,当没有用户时不要渲染行:

class Users extends React.Component {

  componentDidMount() {
        this.props.loadUsers();
  }

  render() {
    const userRows = this.props.users ? 
      (
        <tbody>
          {this.props.users.map((user, i) => (
            <UserListItem firstName={user.profile.firstName} lastName={user.profile.lastName} email={user.email} key={i} />
           ))}
        </tbody>
      ) : null

    return (
      <PageWrapper>
          <table className="w-full text-left table-collapse">
            <thead>
              <tr className="text-sm text-grey-darker bg-grey-lightest">
                <TableTH name="Name" />
                <TableTH name="Email" />
              </tr>
            </thead>

           {userRows}
          </table>
      </PageWrapper>
    );
  }
}

function TableTH(props) {
    return (
        <th className="p-2">{props.name}</th>
    )
}

function mapStateToProps(state, props) {  
  if(state.user.data) {
    return { users: state.user.data }
  } else {
    return {};
  }
}

export default connect(mapStateToProps, { loadUsers })(Users); 

另一种方法是保持 INITIAL_STATE 的当前状态,并确保在 Users props 中始终有一个可迭代的 users 键。您可以将mapStateToProps 修改为:

function mapStateToProps(state, props) {  
  return { users: state.user.data ? state.user.data : [] };
}

【讨论】:

  • 谢谢,是的,这行得通,但我犹豫了,因为它看起来很臭。这是最佳做法吗?
  • @99miles,所以我认为它是conditional rendering 的一种形式。如果您希望它“更清洁”,那么我认为您必须重构(可能)更多组件。你的TypeError 的根源是你假设this.props.users 存在于props 中,但它可能不取决于状态/INITIAL_STATE...所以你必须以某种方式考虑这一点。
  • 另一种方法(可能不那么臭?)是更改您的Users mapStateToProps 以便在props 中始终有一个可迭代的users 键。例如,返回{users: state.user.data ? state.user.data : []}
猜你喜欢
  • 2021-01-02
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
  • 2016-02-18
  • 1970-01-01
  • 2021-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多