#reactjs #react-redux
#reactjs #react-redux
Вопрос:
Мне нужно отобразить вложенный массив. Но я не могу отобразить вложенный список, поскольку мое хранилище redux не обновляется. Ниже приведен пример структуры данных:
{
email: "fgh@gmail.com"
tId: 2
teacherClasses: null
teacherUserRef: 3
user:
{
admin: null
firstName: "fgh"
id: 3
lastName: "fgh"
}}
Я не могу отобразить ничего, что находится внутри пользователя.
ниже приведен код:
Редуктор:
import { ACTION_TYPES } from "../actions/teacher";
const initialState = {
list: []
}
export const teacher = (state = initialState, action) => {
switch (action.type) {
case ACTION_TYPES.FETCH_ALL:
return {
...state,
list: [
...action.payload]
}
case ACTION_TYPES.FETCHBYID:
return {
...state,
list: [action.payload]
}
case ACTION_TYPES.CREATE:
return {
...state,
list: [...state.list, action.payload]
}
case ACTION_TYPES.UPDATE:
return {
...state,
list: state.list.map(x => x.id == action.payload.id ? action.payload : x)
}
case ACTION_TYPES.DELETE:
return {
...state,
list: state.list.filter(x => x.id != action.payload)
}
default:
return state
}
}
Страница компонента:
Teacher.js:
const Teacher = ({ ...props }) => {
const [currentId, setCurrentId] = useState(0)
useEffect(() => {
console.log("teacher call")
props.fetchAllTeacher()
console.log(props.teacherList)
}, [currentId])//componentDidMount
return (
<div className="site-layout-background" style={{ padding: 24, textAlign: 'center' }}>
<Space direction="vertical" align="center">
<TableContainer>
<Table>
<TableHead >
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Email</TableCell>
<TableCell></TableCell>
</TableRow>
{
props.teacherList.map((record, index) => {
return (<TableRow key={index} hover>
<TableCell>{record.email}</TableCell>
<TableCell>{record.user.firstName}</TableCell>
<TableCell>
<ButtonGroup variant="text">
<Button icon={<DeleteOutlined />} onClick={() => onDelete(record.user.id)}></Button>
</ButtonGroup>
</TableCell>
</TableRow>)
})}
</TableHead>
<TableBody>
</TableBody>
</Table>
</TableContainer>
</Space>
</div>
);
}
const mapStateToProps = state => ({
teacherList: state.teacher.list,
userList: state.user.list
})
const mapActionToProps = {
fetchAllTeacher: actions.fetchAll,
deleteUser: actions1.Delete
}
export default connect(mapStateToProps, mapActionToProps)(Teacher);
Создатель действия:
import api from "./api";
export const ACTION_TYPES = {
CREATE: 'CREATE',
UPDATE: 'UPDATE',
DELETE: 'DELETE',
FETCH_ALL: 'FETCH_ALL',
FETCHBYID: 'FETCHBYID'
}
export const fetchAll = () => dispatch => {
api.teacher().fetchAll()
.then(response => {
dispatch({
type: ACTION_TYPES.FETCH_ALL,
payload: response.data
})
})
.catch(err => console.log(err))
}
export const fetchById = (id) => dispatch => {
api.teacher().fetchById(id)
.then(response => {
dispatch({
type: ACTION_TYPES.FETCHBYID,
payload: response.data
})
})
.catch(err => console.log(err))
}
export const create = (data, onSuccess) => dispatch => {
api.teacher().create(data)
.then(res => {
dispatch({
type: ACTION_TYPES.CREATE,
payload: res.data
})
onSuccess()
})
.catch(err => console.log(err))
}
export const update = (id, data, onSuccess) => dispatch => {
api.teacher().update(id, data)
.then(res => {
dispatch({
type: ACTION_TYPES.UPDATE,
payload: { id, ...data }
})
onSuccess()
})
.catch(err => console.log(err))
}
export const Delete = (id, onSuccess) => dispatch => {
api.teacher().delete(id)
.then(res => {
dispatch({
type: ACTION_TYPES.DELETE,
payload: id
})
onSuccess()
})
.catch(err => console.log(err))
}
Я получаю сообщение об ошибке, в котором указано, что FirstName не определено.
Пожалуйста, помогите.
Ответ №1:
- Рекомендация
Поскольку вы используете функциональный компонент, вам следует использовать react-redux
такие перехваты, как useSelector
, useDispatch
.
import { useSelector, useDispatch } from "react-redux"
...
teacherList = useSelect(state => state.teacher.list)
userList = useSelect(state => state.user.list)
const dispatch = useDispatch()
...
{
dispatch(actions.fetchAll(...))
dispatch(actions1.Delete(...))
}
- Проблема
Во-первых, вам не нужно устанавливать currentId
как зависимость useEffect
.
Когда зависимость представляет собой пустой список, обратный вызов будет выполняться только один раз, аналогично componentDidMount
.
Во-вторых, fetchAllTeacher
это асинхронное действие, которое означает, что вам нужно подождать, пока все учителя не будут успешно извлечены.
Итак, вам нужно добавить функцию отложенной загрузки.
Комментарии:
1. Большое спасибо. Я буду использовать useSelector, useDispatch.. Но это вызывает проблемы?
2. Я рекомендую использовать его. Это не обязательно. Кстати, пожалуйста, поделитесь
console.log(props.teacherList)
результатом.3. спасибо за ваше время. ниже приведен результат:
0: email: "pashmina@gmail.com" tId: 1 teacherClasses: null teacherUserRef: 2 user: admin: null firstName: "pashmina" id: 2 __proto__: Object __proto__: Object 1: email: "vijeth@gmail.com" tId: 2006 teacherClasses: null teacherUserRef: 1013 user: admin: null firstName: "vjv" id: 1013 __proto__: Object __proto__: Object 2: email: "shyamal.bhat@gmail.com" tId: 2007 teacherClasses: null teacherUserRef: 1014 user: admin: null firstName: "lamini" id: 1014
4. результат всегда задерживается
5. Попробуйте {record.user? .FirstName}
Ответ №2:
Причина, по которой ваше хранилище redux не обновляется, заключается в том, что вы должны отправить действия. Правильная подпись для mapDispatchToProps
:
const mapDispatchToProps = (dispatch) => {
fetchAllTeacher: () => dispatch(actions.fetchAll()),
deleteUser: (id) => dispatch(actions.Delete(id)),
}
export default connect(mapStateToProps, mapDispatchToProps)(Teacher);
НО есть лучший способ. На самом деле вы смешиваете две парадигмы, и, хотя вышеупомянутое будет работать, вам следует использовать перехваты redux, поскольку вы создали функциональный компонент и уже используете useEffect
перехват.
Это может работать следующим образом:
import { useSelector, useDispatch } from "react-redux"
const Teacher = ({ ...props }) => {
const dispatch = useDispatch();
useEffect(() => {
console.log("teacher call")
const teachers = props.fetchAllTeacher();
// dispatch the action that will add the list to the redux state
dispatch(actions.fetchAll(teachers));
}, [currentId]);
// fetch the teacher list from redux store
const teacherList = useSelector(state => state.teacher.list);
return (...);
}
Рассмотрите возможность перемещения определения селектора state => state.teacher.list
в его собственный модуль, чтобы вы могли повторно использовать его в других компонентах и обновлять его в одном месте, если структура вашего хранилища изменится.
Похоже, что в вашем коде не было отправлено никаких действий, поэтому проблема не была связана с вложенностью данных. У вас могут быть вложенные данные в вашем состоянии без проблем.
Комментарии:
1. Большое спасибо. Я удостоверюсь, что не будет смешиваться. Я тоже отправляю действия. Я отредактировал свой вопрос. Пожалуйста, проверьте