Javascript 获取error state.stories是不可编辑的

Javascript 获取error state.stories是不可编辑的,javascript,arrays,reactjs,redux,state,Javascript,Arrays,Reactjs,Redux,State,我正在创建一个react/redux应用程序,用户可以在其中登录并通过提交表单添加故事。故事作为一个对象提交,我想将这个故事添加到数组的对象中。但我不断收到一个错误,说state.stories不可编辑,即使我在reducer中编写stories:[…state.stories,action.payload]。action.payload返回一个对象,我想将该对象放入数组中。 如何将action.payload对象插入数组?我希望故事是一组对象。 对于任何格式错误,我深表歉意 App.js im

我正在创建一个react/redux应用程序,用户可以在其中登录并通过提交表单添加故事。故事作为一个对象提交,我想将这个故事添加到数组的对象中。但我不断收到一个错误,说
state.stories不可编辑
,即使我在reducer中编写
stories:[…state.stories,action.payload]
。action.payload返回一个对象,我想将该对象放入数组中。 如何将action.payload对象插入数组?我希望故事是一组对象。 对于任何格式错误,我深表歉意

App.js

import './App.scss';
import Login from './components/Login';
import { Router, Switch, Route, NavLink } from 'react-router-dom';
import PrivateRoute from './utils/PrivateRoute';
import CreateStory from './components/CreateStory';
import history from './utils/history';

function App() {


  return (
    <div className="App">

      <Router history={history}>
        <Switch>
          <Route exact path="/" component={Login} />
          <PrivateRoute path="/user" component={CreateStory}/>

        </Switch>
      </Router>
    </div>
  );
}

export default App;
initialState.js:

import { getToken } from '../utils/Common'

export const initialState = {
    isLoggedIn: false,
    userId: '',
    role: 'user',
    token: getToken,
    data: '',
  };
reducers.js

import { initialState } from './initialState';
import * as t from './actionTypes';

export const loginReducer = (state = initialState, action) => {
  switch (action.type) {
    case t.SET_ROLE_STATE:
      return {
        ...state,
        role: action.payload,
      };
    case t.SET_LOGIN_STATE:
      return {
        ...state,
        ...action.payload, // this is what we expect to get back from API call and login page input
        isLoggedIn: true, // we set this as true on login
      };
    default:
      return state;
  } 
};

export const storyReducer = (state = initialState, action) => {
  switch (action.type) {
    case t.CREATE_STORY:
      return {
        ...state,
        story: [...state.stories, action.payload],   //the error pops up at this line
      };
    default:
      return state;
  } 
}
actions.js:

import * as t from './actionTypes';
import { setUserSession } from '../utils/Common';

// this is what our action should look like which dispatches the "payload" to reducer
const setLoginState = (loginData) => {
  return {
    type: t.SET_LOGIN_STATE,
    payload: loginData, //{ ...json, userId: email }
  };
};

const setStoryState = (storyData) => {
    return {
      type: t.CREATE_STORY,
      payload: storyData,
    };
  };

export const login = (loginInput) => { //our login action
    const { email, password } = loginInput;
    return (dispatch) => {  // don't forget to use dispatch here!
      return fetch('http://localhost:3000/api/v1/signin', {
        method: 'POST',
        headers: {  
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(loginInput),
      })
        .then((response) => response.json()) //json will be the response body
        .then((json) => {
        // if (json.msg === 'success') { // response success checking logic could differ
           // console.log(json)
            dispatch(setLoginState({ ...json, userId: email })); // our action is called here with object as parameter, this is our payload
            //we appended json object to our state
            //   } else {
        //     alert('Login Failed', 'Email or Password is incorrect');
        //  }
            setUserSession(json.token, json.lastName)
        })
        .catch((err) => {
          alert('Login Failed', 'Some error occured, please retry');
          console.log(err);
        });
    };
};

export const roleChange = role => {
    return {
        type: t.SET_ROLE_STATE,
        payload: role
      };
}



  export const createStory = storyInput => {
    const { summary, description, type, complexity, time, cost } = storyInput;
    return (dispatch) => {  // don't forget to use dispatch here!
      return fetch('http://localhost:3000/api/v1/stories', {
        method: 'POST',
        headers: {  
          Accept: 'application/json',
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${token}`,
        },
        body: JSON.stringify(storyInput),
      })
        .then((response) => response.json()) //json will be the response body
        .then((json) => {
        // if (json.msg === 'success') { // response success checking logic could differ
            console.log(json)
            dispatch(setStoryState({  // our action is called here with object as parameter, this is our payload
                summary: summary,
                description: description,
                type: type,
                complexity: complexity,
                time: time,
                cost: cost
            })); // our action is called here
        //   } else {
        //     alert('Login Failed', 'Email or Password is incorrect');
        //  }
        })
        .catch((err) => {
          alert('Some error occured, please retry');
          console.log(err);
        });
    };
}
Common.js

// return the user data from the session storage
export const getUser = () => {
    const userStr = sessionStorage.getItem('user');
    if (userStr) return JSON.parse(userStr);
    else return null;
}
   
// return the token from the session storage
export const getToken = () => {
    return sessionStorage.getItem('token') || null;
}
   
// remove the token and user from the session storage
export const removeUserSession = () => {
    sessionStorage.removeItem('token');
    sessionStorage.removeItem('user');
}
   
// set the token and user from the session storage
export const setUserSession = (token, user) => {
    sessionStorage.setItem('token', token);
    sessionStorage.setItem('user', JSON.stringify(user));
}
更新: 我已更改为:

export const storyReducer = (state = {stories: []}, action) => {
  switch (action.type) {
    case t.CREATE_STORY:
      return {
        ...state,
        stories: [...state, action.payload],
      };
    // case t.ADD_STORY:
    //   return {
    //     ...state,
    //     stories: [...state.stories, action.payload], //stories is an object
    //   };
    default:
      return state;
  } 
}

现在,当添加第一个故事时,我没有得到错误。但是我在向数组中添加多个存储时出错。

您对
loginReducer
storyReducer
使用了相同的
initialState
,而后者实际上无法使用,因为它没有
stories
属性,因此您试图传播
未定义的


使用两种不同的初始状态。它们也不必有这个名称,您可以随意命名;)

您的
initialState
不包含
stories
属性,因此
initialState。stories
未定义的
,而
未定义的
是不可修改的。@secan我尝试过,但运气不好:(仍然会收到相同的错误消息您也有一个输入错误,请检查您所说的显示错误的行。您有
story:[…state.stories,action.payload],
而不是
stories:[…state.stories]
。请确保在初始状态下为
stories
数组设置默认值,如前面提到的@secan。尝试检查
state.stories
是否存在,然后添加else块进行调试。这将给出不可编辑的位置。我已将其更改为storyReducer=(state={stories:[],action)现在我可以将第一个故事添加到故事数组中,当我尝试添加另一个故事时,我得到了相同的错误。好了,现在我仍然无法添加任何内容,获得相同的数组,故事数组正在清空设置相同的*错误哦,还有,您的
创建故事
减速机应该有
故事:[…state.stories,action.payload],
而不是
故事:[…状态,动作.有效载荷],
另外,我建议你看看官方的redux教程和现代redux-你在这里写的是一种非常古老的redux风格,我们不再推荐了。所有这些事情可能都不会发生在现代redux上,所以看看;)
import { initialState } from './initialState';
import * as t from './actionTypes';

export const loginReducer = (state = initialState, action) => {
  switch (action.type) {
    case t.SET_ROLE_STATE:
      return {
        ...state,
        role: action.payload,
      };
    case t.SET_LOGIN_STATE:
      return {
        ...state,
        ...action.payload, // this is what we expect to get back from API call and login page input
        isLoggedIn: true, // we set this as true on login
      };
    default:
      return state;
  } 
};

export const storyReducer = (state = initialState, action) => {
  switch (action.type) {
    case t.CREATE_STORY:
      return {
        ...state,
        story: [...state.stories, action.payload],   //the error pops up at this line
      };
    default:
      return state;
  } 
}
import * as t from './actionTypes';
import { setUserSession } from '../utils/Common';

// this is what our action should look like which dispatches the "payload" to reducer
const setLoginState = (loginData) => {
  return {
    type: t.SET_LOGIN_STATE,
    payload: loginData, //{ ...json, userId: email }
  };
};

const setStoryState = (storyData) => {
    return {
      type: t.CREATE_STORY,
      payload: storyData,
    };
  };

export const login = (loginInput) => { //our login action
    const { email, password } = loginInput;
    return (dispatch) => {  // don't forget to use dispatch here!
      return fetch('http://localhost:3000/api/v1/signin', {
        method: 'POST',
        headers: {  
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(loginInput),
      })
        .then((response) => response.json()) //json will be the response body
        .then((json) => {
        // if (json.msg === 'success') { // response success checking logic could differ
           // console.log(json)
            dispatch(setLoginState({ ...json, userId: email })); // our action is called here with object as parameter, this is our payload
            //we appended json object to our state
            //   } else {
        //     alert('Login Failed', 'Email or Password is incorrect');
        //  }
            setUserSession(json.token, json.lastName)
        })
        .catch((err) => {
          alert('Login Failed', 'Some error occured, please retry');
          console.log(err);
        });
    };
};

export const roleChange = role => {
    return {
        type: t.SET_ROLE_STATE,
        payload: role
      };
}



  export const createStory = storyInput => {
    const { summary, description, type, complexity, time, cost } = storyInput;
    return (dispatch) => {  // don't forget to use dispatch here!
      return fetch('http://localhost:3000/api/v1/stories', {
        method: 'POST',
        headers: {  
          Accept: 'application/json',
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${token}`,
        },
        body: JSON.stringify(storyInput),
      })
        .then((response) => response.json()) //json will be the response body
        .then((json) => {
        // if (json.msg === 'success') { // response success checking logic could differ
            console.log(json)
            dispatch(setStoryState({  // our action is called here with object as parameter, this is our payload
                summary: summary,
                description: description,
                type: type,
                complexity: complexity,
                time: time,
                cost: cost
            })); // our action is called here
        //   } else {
        //     alert('Login Failed', 'Email or Password is incorrect');
        //  }
        })
        .catch((err) => {
          alert('Some error occured, please retry');
          console.log(err);
        });
    };
}
// return the user data from the session storage
export const getUser = () => {
    const userStr = sessionStorage.getItem('user');
    if (userStr) return JSON.parse(userStr);
    else return null;
}
   
// return the token from the session storage
export const getToken = () => {
    return sessionStorage.getItem('token') || null;
}
   
// remove the token and user from the session storage
export const removeUserSession = () => {
    sessionStorage.removeItem('token');
    sessionStorage.removeItem('user');
}
   
// set the token and user from the session storage
export const setUserSession = (token, user) => {
    sessionStorage.setItem('token', token);
    sessionStorage.setItem('user', JSON.stringify(user));
}
export const storyReducer = (state = {stories: []}, action) => {
  switch (action.type) {
    case t.CREATE_STORY:
      return {
        ...state,
        stories: [...state, action.payload],
      };
    // case t.ADD_STORY:
    //   return {
    //     ...state,
    //     stories: [...state.stories, action.payload], //stories is an object
    //   };
    default:
      return state;
  } 
}