Как отправить действие при загрузке страницы в Reaction-Redux?
Я должен отобразить таблицу с большим количеством данных. Есть кнопка нумерации страниц, которая отображает 10 записей на странице. У меня есть одна кнопка с именем "FETCH", при нажатии на нее таблица заполняется. Как загрузить мою таблицу при загрузке страницы.
action.js
import fetch from 'isomorphic-fetch';
export const ADD_BENEFICIARY = 'ADD_BENEFICIARY';
export const REMOVE_BENEFICIARY = 'REMOVE_BENEFICIARY';
export const ADD_PLAN_TO_COMPARE = 'ADD_PLAN_COMPARE';
export const REMOVE_PLAN_FROM_COMPARE = 'REMOVE_PLAN_COMPARE';
export const SHOW_PLAN_COMPARE = 'SHOW_PLAN_COMPARE';
export const NEXT_PAGE_PLAN_LIST = 'NEXT_PAGE_PLAN_LIST';
export const PREV_PAGE_PLAN_LIST = 'PREV_PAGE_PLAN_LIST';
export const REQUEST_PAGE_PLAN_LIST = 'REQUEST_PAGE_PLAN_LIST';
export const RECEIVE_PAGE_PLAN_LIST = 'RECEIVE_PAGE_PLAN_LIST';
export const showNextPageOfPlans = () => {
return {
type: NEXT_PAGE_PLAN_LIST
}
}
export const showPreviousPageOfPlans = () => {
return {
type: PREV_PAGE_PLAN_LIST
}
}
export const requestPageOfPlans = (startIdx, pageSize) => {
return {
type: REQUEST_PAGE_PLAN_LIST,
start: startIdx,
pageSize: pageSize
}
}
export const receivePageOfPlans = (startIdx, json) => {
return {
type: RECEIVE_PAGE_PLAN_LIST,
start: startIdx,
plans: json
}
}
export const fetchPlans = (startIdx, pageSize) => {
var str = sessionStorage.getItem('formValue'); //JSON.stringify(formValues);
return function (dispatch) {
dispatch(requestPageOfPlans(startIdx, pageSize));
return fetch('http://172.16.32.57:9090/alternatePlans/plans/list/', {method: 'post', body: str, headers: new Headers({'Content-Type': 'application/json'}) })
.then(response => response.json())
.then(json =>
dispatch(receivePageOfPlans(startIdx, json))
)
}
}
reducer.js
import { REQUEST_PAGE_PLAN_LIST, RECEIVE_PAGE_PLAN_LIST,
NEXT_PAGE_PLAN_LIST, PREV_PAGE_PLAN_LIST } from './actions';
const initialPaging = {
startIndex: 0,
lastIndex: 0,
pageSize: 10
}
const paging = (state = initialCurrentPage, action) => {
switch (action.type) {
case NEXT_PAGE_PLAN_LIST:
if (state.startIndex+state.pageSize <= state.lastIndex) {
return { ...state, startIndex: state.startIndex+state.pageSize };
}
else {
return state;
}
case PREV_PAGE_PLAN_LIST:
if (state.startIndex-state.pageSize >= 0) {
return { ...state, startIndex: state.startIndex-state.pageSize };
}
else {
return state;
}
case REQUEST_PAGE_PLAN_LIST:
return { ...state, isFetching: true };
case RECEIVE_PAGE_PLAN_LIST:
return { ...state, isFetching: false };
default:
return state;
}
}
var initialPlans = [];
const plans = (state = initialPlans, action) => {
switch (action.type) {
case RECEIVE_PAGE_PLAN_LIST:
return action.plans.plans;
default:
return state;
}
}
const allReducers = (state = {}, action) => {
let items = plans(state.plans, action);
return {
plans: items,
paging: paging({ ...initialPaging, ...state.paging, lastIndex: items.length-1 }, action)
}
}
export default allReducers;
PS Я новичок в реакции-редуксе. Официальная документация хороша, но объяснений очень мало.
3 ответа
Вы называете это из componentDidMount()
компонента реакции для вашей страницы или там, где это имеет смысл. Итак, в этом файле компонента:
import { requestPageOfPlans } from 'actions';
import React from 'react';
import { connect } from 'react-redux';
class MyComponent extends React.Component {
componentDidMount() {
this.props.requestPageOfPlans();
}
}
export default connect((state) => state, { requestPageOfPlans })(MyComponent);
Таким образом, ключ здесь - настройка соединения. Первый параметр - это то, как вы хотите преобразовать состояние (ваши редукторы) в данные для реквизита. Отрегулируйте это, как вам нужно. Второй - какие действия вы хотите связать. Вы также можете импортировать отправку вручную, но мне лично нравится этот шаблон. Он устанавливает действия как реквизиты для компонента, и вы можете называть это так. Просто передайте аргументы, как вам нужно. Эта страница здесь: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options объясняет функцию подключения более подробно.
редактировать
Учитывая, что вы разбиваете страницы на внешний интерфейс, вам нужно настроить функцию connect mapStateToProps, чтобы передать данные разбивки на страницы компоненту, а затем просмотреть их, чтобы отобразить то, что вам нужно. Лично я бы делал нумерацию страниц на сервере и просто делал новые запросы для каждой страницы. Зависит от того, сколько записей вы ожидаете иметь.
Так что в подключении сделать что-то вроде этого:
export default connect((state) => {
return {
startIndex: state.paging.lastIndex,
pageSize: state.paging.pageSize,
lastIndex: state.paging.lastIndex,
plans: state.plans
};
}, { requestPageOfPlans })(MyComponent);
Затем в вашем компоненте выполните цикл по планам, используя эти индексы:
render() {
const plans = [];
const maxIndex = Math.min(this.props.startIndex + this.props.pageSize, this.props.lastIndex);
for (let i = this.props.startIndex || 0; i < maxIndex; i++) {
const plan = this.props.plans[i];
plans.push(<Plan key={plan.id} plan={plan} />);
}
return (
<ul>{plans}</ul>
);
}
Снова сделаем некоторые предположения о том, как вы планируете его визуализировать, если у вас есть компонент с именем "План" и т. Д. Но примерно так вы можете работать с ним.
componentDidMount - подходящее время для загрузки вашей первой страницы.
Кстати, на мой взгляд, смена страницы - это не действие, это просто какой-то параметр для загрузки ваших данных.
ActionCreator
const userurl = '/rest/users'
export const loadUsers = (page = 0) => {
return (dispatch) => {
axios.get(userurl+"?page="+page)
.then(function(resp) {
dispatch(loadUsersOK(resp.data._embedded.users, resp.data.page));
})
.catch(function(error) {
...
})
};
}
Компонент JSX
<span style={{marginRight:15, fontSize: 14, color: '#333'}}>{page.number*page.size+1}-{page.number*page.size+page.size} of {' '} {page.totalElements}</span>
<FlatButton style={flatButtonStyle} icon={<NavigationChevronLeft/>} onTouchTap={this.prevPage} />
<FlatButton style={flatButtonStyle} icon={<NavigationChevronRight/>} onTouchTap={this.nextPage} />
Обработчики компонентов
prevPage() {
const { page } = this.props.users;
this.props.loadUsers(page.number - 1);
}
nextPage() {
const { page } = this.props.users;
this.props.loadUsers(page.number + 1);
}
соединять
const mapStateToProps = state => {
return {
users: state.users
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
loadUsers: (page=0) => dispatch(loadUsers(page))
}
}
const Wrapped = connect(
mapStateToProps,
mapDispatchToProps
)(Users)
ТОЛЬКО ОДИН ДЕЙСТВИЕ
export const loadUsersOK = (result, page) => ({
type: LOAD_USERS_OK,
result,
page
})
Пусть это поможет.
Ответы кажутся устаревшими. Появился новый API-крючок. ВместоcomponentDidMount
теперь вам следует использоватьuseEffect
с пустым массивом зависимостей для отправки действия при загрузке страницы.
export const MyComponent = () => {
const dispatch = useAppDispatch();
const entities = useAppSelector((state) => state.entities);
useEffect(() => {
dispatch(myThunk());
}, []);
return <div>My Entities Length is {entities.length}</div>
}