Тощилин Сергей
setState
this.setState((state, props) => {
return { counter: state.counter + props.step };
})
render()
export const notesReducer = (
state: ApplicationState,
action: IAction
) => {
switch (action.type) {
case 'INCREMENT_NOTE_COUNTER': {
const { noteCount } = state;
const { newNoteCount } = action;
return {
...state,
noteCount: noteCount + newNoteCount
};
}
...
export const notesReducer = (
state: ApplicationState,
action: IAction
) => {
switch (action.type) {
case 'INCREMENT_NOTE_COUNTER': {
const { noteCount } = state;
const { newNoteCount } = action;
return {
...state,
noteCount: noteCount + newNoteCount
};
}
...
export const notesReducer = (
state: ApplicationState,
action: IAction
) => {
switch (action.type) {
case 'INCREMENT_NOTE_COUNTER': {
const { noteCount } = state;
const { newNoteCount } = action;
return {
...state,
noteCount: noteCount + newNoteCount
};
}
...
export enum NOTE_STATUS {
actual = 'actual',
old = 'old',
deleted = 'deleted'
}
interface IPureNote { ... }
export interface INote extends IPureNote { ... }
export enum ACTIONS { ... }
export enum NOTE_STATUS { ... }
export interface IPureNote {
title: string;
description: string;
status: NOTE_STATUS;
created: Date;
}
export interface INote extends IPureNote {
id: number;
}
export enum ACTIONS { ... }
export enum NOTE_STATUS { ... }
export interface IPureNote { ... }
export interface INote extends IPureNote { ... }
// Все типы Action'ов
export enum ACTIONS {
ADD_NOTE = 'ADD_NOTE',
EDIT_NOTE = 'EDIT_NOTE',
CHANGE_STATUS = 'CHANGE_STATUS'
}
// Payloads – ПОЛЕЗНАЯ(!) информация, которая передается в action
export interface IEditNotePayload {
id: number;
newNote: IPureNote;
}
export interface IAddNotePayload { ... }
export interface IChangeStatusPayload { ... }
// Интерфейс, который описывает Action целиком
export interface IAction { ... }
// Payloads – ПОЛЕЗНАЯ(!) информация, которая передается в action
export interface IAddNotePayload { ... }
export interface IEditNotePayload { ... }
export interface IChangeStatusPayload { ... }
// Интерфейс, который описывает Action целиком
export interface IAction {
type: ACTIONS;
payload:
| IAddNotePayload
| IEditNotePayload
| IChangeStatusPayload;
}
import {
IAddNotePayload,
IEditNotePayload,
IChangeStatusPayload,
ACTIONS,
IAction
} from '../common/types';
export const editNote = ({ id, newNote }: IEditNotePayload): IAction =>
({
type: ACTIONS.EDIT_NOTE,
payload: {
id,
newNote
}
});
import {
IAddNotePayload,
IEditNotePayload,
IChangeStatusPayload,
ACTIONS,
IAction
} from '../common/types';
export const editNote = ({ id, newNote }: IEditNotePayload): IAction =>
({
type: ACTIONS.EDIT_NOTE,
payload: {
id,
newNote
}
});
import {
IAddNotePayload,
IEditNotePayload,
IChangeStatusPayload,
ACTIONS,
IAction
} from '../common/types';
export const editNote = ({ id, newNote }: IEditNotePayload): IAction =>
({
type: ACTIONS.EDIT_NOTE,
payload: {
id,
newNote
}
});
import {
IAddNotePayload,
IEditNotePayload,
IChangeStatusPayload,
ACTIONS,
IAction
} from '../common/types';
export const editNote = ({ id, newNote }: IEditNotePayload): IAction =>
({
type: ACTIONS.EDIT_NOTE,
payload: {
id,
newNote
}
});
import { ..., IEditNotePayload, IAction } from '../common/types';
...
// состояние Store при инициализации приложения
export const initialState = { notes: initialNotes };
const notesReducer = (
state: ApplicationState = initialState,
action: IAction
) => {
...
switch (action.type) {
case ACTIONS.EDIT_NOTE:
...
}
};
import { ..., IEditNotePayload, IAction } from '../common/types';
...
// состояние Store при инициализации приложения
export const initialState = { notes: initialNotes };
const notesReducer = (
state: ApplicationState = initialState,
action: IAction
) => {
...
switch (action.type) {
case ACTIONS.EDIT_NOTE:
...
}
};
import { ..., ACTIONS, IAction } from '../common/types';
...
// состояние Store при инициализации приложения
export const initialState = { notes: initialNotes };
const notesReducer = (
state: ApplicationState = initialState,
action: IAction
) => {
...
switch (action.type) {
case ACTIONS.EDIT_NOTE:
...
}
};
import { ..., IEditNotePayload, IAction } from '../common/types';
...
// состояние Store при инициализации приложения
export const initialState = { notes: initialNotes };
const notesReducer = (
state: ApplicationState = initialState,
action: IAction
) => {
...
switch (action.type) {
case ACTIONS.EDIT_NOTE:
...
}
};
import { ApplicationState } from './index';
...
case ACTIONS.EDIT_NOTE: {
const { id, newNote } = action.payload;
const noteWithId = { ...newNote, id };
const noteIndex = state.notes.findIndex(
(note: INote) => note.id === id
);
return {
...state,
notes: [...state.notes].splice(noteIndex, 1, noteWithId);
};
}
...
import { ApplicationState } from './index';
...
case ACTIONS.EDIT_NOTE: {
const { id, newNote } = action.payload;
const noteWithId = { ...newNote, id };
const noteIndex = state.notes.findIndex(
(note: INote) => note.id === id
);
return {
...state,
notes: [...state.notes].splice(noteIndex, 1, noteWithId);
};
}
...
import { createStore } from 'redux';
import { INote } from '../common/types';
import reducer, { initialState } from './reducers';
export interface ApplicationState {
notes: INote[];
}
export default createStore(
reducer,
initialState as any
);
import { createStore } from 'redux';
import { INote } from '../common/types';
import reducer, { initialState } from './reducers';
export interface ApplicationState {
notes: INote[];
}
export default createStore(
reducer,
initialState as any
);
import { createStore } from 'redux';
import { INote } from '../common/types';
import reducer, { initialState } from './reducers';
export interface ApplicationState {
notes: INote[];
}
export default createStore(
reducer,
initialState as any
);
import { createStore } from 'redux';
import { INote } from '../common/types';
import reducer, { initialState } from './reducers';
export interface ApplicationState {
notes: INote[];
}
export default createStore(
reducer,
initialState as any
);
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import store from './store';
export default class App extends Component {
public render() {
return (
<Provider store={store}>
<div className="App">
<Switch>
<Route path="/note/:id" component={Note} />
<Route path="/" component={NotesList} />
</Switch>
</div>
</Provider>
);
}
}
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import store from './store';
export default class App extends Component {
public render() {
return (
<Provider store={store}>
<div className="App">
<Switch>
<Route path="/note/:id" component={Note} />
<Route path="/" component={NotesList} />
</Switch>
</div>
</Provider>
);
}
}
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import store from './store';
export default class App extends Component {
public render() {
return (
<Provider store={store}>
<div className="App">
<Switch>
<Route path="/note/:id" component={Note} />
<Route path="/" component={NotesList} />
</Switch>
</div>
</Provider>
);
}
}
import { connect } from 'react-redux';
import { ApplicationState } from '../../store';
import { changeStatus, editNote } from '../../store/actions';
...
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps & ...;
class Note extends Component<Props, IOwnState> {
...
}
const mapStateToProps = (state: ApplicationState, props: OwnProps) => ({
currentNote: state.notes.find(note => note.id === props.id);
});
export default connect(mapStateToProps)(Note);
import { connect } from 'react-redux';
import { ApplicationState } from '../../store';
import { changeStatus, editNote } from '../../store/actions';
...
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps & ...;
class Note extends Component<Props, IOwnState> {
...
}
const mapStateToProps = (state: ApplicationState, props: OwnProps) => ({
currentNote: state.notes.find(note => note.id === props.id);
});
export default connect(mapStateToProps)(Note);
import { connect } from 'react-redux';
import { ApplicationState } from '../../store';
import { changeStatus, editNote } from '../../store/actions';
...
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps & ...;
class Note extends Component<Props, IOwnState> {
...
}
const mapStateToProps = (state: ApplicationState, props: OwnProps) => ({
currentNote: state.notes.find(note => note.id === props.id);
});
export default connect(mapStateToProps)(Note);
...
type StateProps = ReturnType<typeof mapStateToProps>;
type Props = StateProps & DispatchProps;
class Note extends Component<Props, IOwnState> {
...
public render() {
return (
...
<div className="note-page__field">
Дата создания
<div className="note-page__created-date">
{this.props.currentNote.created}
</div>
</div>
...
)
}
...
}
...
type StateProps = ReturnType<typeof mapStateToProps>;
type Props = StateProps & DispatchProps;
class Note extends Component<Props, IOwnState> {
...
public render() {
return (
...
<div className="note-page__field">
Дата создания
<div className="note-page__created-date">
{this.props.currentNote.created}
</div>
</div>
...
)
}
...
}
...
...
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps;
class Note extends Component<Props, IOwnState> {
...
public onEditButtonClick = (e: ReactMouseEvent) => {
...
// Кладем в currentNote данные об отредактированной заметке
const currentNote = ...;
this.props.dispatch({
type: ACTIONS.EDIT_NOTE,
payload: { id, newNote: currentNote }
});
};
...
}
...
...
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps;
class Note extends Component<Props, IOwnState> {
...
public onEditButtonClick = (e: ReactMouseEvent) => {
...
// Кладем в currentNote данные об отредактированной заметке
const currentNote = ...;
this.props.dispatch({
type: ACTIONS.EDIT_NOTE,
payload: { id, newNote: currentNote }
});
};
...
}
...
import { editNote } from '../../store/actions';
...
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps;
class Note extends Component<Props, IOwnState> {
...
public onEditButtonClick = (e: ReactMouseEvent) => {
...
// Кладем в currentNote данные об отредактированной заметке
const currentNote = ...;
this.props.dispatch(editNote({ id, newNote: currentNote }));
};
...
}
...
import { editNote } from '../../store/actions';
...
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps;
class Note extends Component<Props, IOwnState> {
...
public onEditButtonClick = (e: ReactMouseEvent) => {
...
// Кладем в currentNote данные об отредактированной заметке
const currentNote = ...;
this.props.dispatch(editNote({ id, newNote: currentNote }));
};
...
}
...
import { editNote } from '../../store/actions';
...
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps;
class Note extends Component<Props, IOwnState> {
...
public onEditButtonClick = (e: ReactMouseEvent) => {
...
// Кладем в currentNote данные об отредактированной заметке
const currentNote = ...;
this.props.dispatch(editNote({ id: [56], newNote: [ЗАМЕТКА] }))
};
...
}
...
import {
IAddNotePayload,
IEditNotePayload,
IChangeStatusPayload,
ACTIONS,
IAction
} from '../common/types';
const editNote = ({ id: [56], newNote: [ЗАМЕТКА] }: IEditNotePayload) =>
({
type: ACTIONS.EDIT_NOTE // 'EDIT_NOTE',
payload: {
id: [56],
newNote: [ЗАМЕТКА]
}
});
...
import { ApplicationState } from './index';
...
case ACTIONS.EDIT_NOTE: { // 'editNote'
const { id: [56], newNote: [ЗАМЕТКА] } = action.payload;
// noteWithId – это [ЗАМЕТКА №56]
const noteWithId = { ...newNote [ЗАМЕТКА], id [56] };
// находим идентификатор редактируемой заметки
const index = state.notes.findIndex((note: INote) => note.id === id);
// копируем массив заметок и вставляем на место старой новую
return {
...state,
notes: [...state.notes].splice(index, 1, noteWithId: [ЗАМЕТКА №56]);
};
}
...
...
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = { dispatch: (action: IAction) => void };
type Props = StateProps & DispatchProps & ...;
class Note extends Component<Props, IOwnState> {
...
}
const mapStateToProps = (state: ApplicationState, props: OwnProps) => ({
currentNote: state.notes.find(note => note.id === id: [56]);
// теперь this.props.currentNote – это [ЗАМЕТКА №56]
});
export default connect(mapStateToProps)(Note);
...
type StateProps = ReturnType<typeof mapStateToProps>;
type Props = StateProps & DispatchProps; // подкладываем StateProps в this.props
class Note extends Component<Props, IOwnState> {
...
public render() {
return (
...
<div className="note-page__field">
Дата создания
<div className="note-page__created-date">
{this.props.currentNote.created} // это [ЗАМЕТКА №56]
</div>
</div>
...
)
}
...
}
...
type StateProps = ReturnType<typeof mapStateToProps>;
type Props = StateProps & DispatchProps; // подкладываем StateProps в this.props
class Note extends Component<Props, IOwnState> {
...
public render() {
return (
...
<div className="note-page__field">
Дата создания
<div className="note-page__created-date">
{this.props.currentNote.created} // это [ЗАМЕТКА №56]
</div>
</div>
...
)
}
...
}
Context provides a way to pass data through the component tree without having to pass props down manually at every level
import { getLastStatus } from '../../store/selectors';
...
type StateProps = ReturnType<typeof mapStateToProps>
const LastStatus = ({ lastStatus }: StateProps) => {
return (
<h2>Cтатус последней заметки: {lastStatus.toString()}<h2>
)
}
function mapStateToProps(state: ApplicationState) {
return {
lastStatus: getLastStatus(state)
};
}
export default connect(mapStateToProps)(LastStatus);
import { getLastStatus } from '../../store/selectors';
...
type StateProps = ReturnType<typeof mapStateToProps>
const LastStatus = ({ lastStatus }: StateProps) => {
return (
<h2>Cтатус последней заметки: {lastStatus.toString()}<h2>
)
}
function mapStateToProps(state: ApplicationState) {
return {
lastStatus: getLastStatus(state)
};
}
export default connect(mapStateToProps)(LastStatus);
import { ApplicationState } from './index';
export function getNoteById(state: ApplicationState, id: string) {
const { notes } = state;
return notes.find(note => note.id === parseInt(id, 10)) ||
notes[notes.length - 1];
}
export function getAllNotes(state: ApplicationState) {
return state.notes;
}
export function getLastStatus({ notes }: ApplicationState) {
return notes[notes.length - 1].status;
}
import { ApplicationState } from './index';
export function getNoteById(state: ApplicationState, id: string) {
const { notes } = state;
return notes.find(note => note.id === parseInt(id, 10)) ||
notes[notes.length - 1];
}
export function getAllNotes(state: ApplicationState) {
return state.notes;
}
export function getLastStatus({ notes }: ApplicationState) {
return notes[notes.length - 1].status;
}
import { ApplicationState } from './index';
export function getNoteById(state: ApplicationState, id: string) {
const { notes } = state;
return notes.find(note => note.id === parseInt(id, 10)) ||
notes[notes.length - 1];
}
export function getAllNotes(state: ApplicationState) {
return state.notes;
}
export function getLastStatus({ notes }: ApplicationState) {
return notes[notes.length - 1].status;
}
import { ApplicationState } from './index';
export function getNoteById(state: ApplicationState, id: string) {
const notes = getAllNotes(state);
return notes.find(note => note.id === parseInt(id, 10)) ||
notes[notes.length - 1];
}
export function getAllNotes(state: ApplicationState) {
return state.notes;
}
export function getLastStatus({ notes }: ApplicationState) {
return notes[notes.length - 1].status;
}
import { getLastStatus } from '../../store/selectors';
...
type StateProps = ReturnType<typeof mapStateToProps>
const LastStatus = ({ lastStatus }: StateProps) => {
console.log('rerender');
return (
<h2>Cтатус последней заметки: {lastStatus.toString()}<h2>
)
}
function mapStateToProps(state: ApplicationState) {
return {
lastStatus: getLastStatus(state)
};
}
export default connect(mapStateToProps)(LastStatus);
import { getLastStatus } from '../../store/selectors';
...
type StateProps = ReturnType<typeof mapStateToProps>
const LastStatus = ({ lastStatus }: StateProps) => {
console.log('rerender');
return (
<h2>Cтатус последней заметки: {lastStatus.toString()}<h2>
)
}
function mapStateToProps(state: ApplicationState) {
return {
lastStatus: getLastStatus(state)
};
}
export default connect(mapStateToProps)(LastStatus);
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
console.log('recomputed last note selector');
const { notes } = state;
return notes[notes.length - 1]
}
export function getLastStatus(state: ApplicationState) {
console.log('recomputed status selector');
return getLastNote(state).status;
}
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
console.log('recomputed last note selector');
const { notes } = state;
return notes[notes.length - 1]
}
export function getLastStatus(state: ApplicationState) {
console.log('recomputed status selector');
return getLastNote(state).status;
}
import { createSelector } from 'reselect'
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
const { notes } = state;
return notes[notes.length - 1]
}
export const getLastStatus = createSelector(
[getLastNote],
(lastNote: INote) => {
return lastNote.status;
}
)
import { createSelector } from 'reselect'
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
const { notes } = state;
return notes[notes.length - 1]
}
export const getLastStatus = createSelector(
[getLastNote],
(lastNote: INote) => {
return lastNote.status;
}
)
import { createSelector } from 'reselect'
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
const { notes } = state;
return notes[notes.length - 1]
}
export const getLastStatus = createSelector(
[getLastNote],
(lastNote: INote) => {
return lastNote.status;
}
)
import { createSelector } from 'reselect'
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
const { notes } = state;
return notes[notes.length - 1]
}
export const getLastStatus = createSelector(
[getLastNote],
(lastNote: INote) => {
return lastNote.status;
}
)
import { createSelector } from 'reselect'
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
console.log('recomputed last note selector');
const { notes } = state;
return notes[notes.length - 1]
}
export const getLastStatus = createSelector(
[getLastNote],
(lastNote: INote) => {
console.log('recomputed status selector');
return lastNote.status;
}
)
import { createSelector } from 'reselect'
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
console.log('recomputed last note selector');
const { notes } = state;
return notes[notes.length - 1]
}
export const getLastStatus = createSelector(
[getLastNote],
(lastNote: INote) => {
console.log('recomputed status selector');
return lastNote.status;
}
)
import { createSelector } from 'reselect'
import { ApplicationState } from './index';
...
export function getLastNote(state: ApplicationState) {
const { notes } = state;
return notes[notes.length - 1]
}
export const getLastStatus = createSelector(
[getLastNote],
(lastNote: INote) => {
return lastNote.status;
}
)
import { createStore } from 'redux';
import { INote } from '../common/types';
import reducer, { initialState } from './reducers';
export interface ApplicationState {
notes: INote[];
}
export default createStore(
reducer,
initialState as any
);
import { createStore } from 'redux';
import thunk from 'redux-thunk';
import { INote } from '../common/types';
import reducer, { initialState } from './reducers';
export interface ApplicationState {
notes: INote[];
}
export default createStore(
reducer,
initialState as any,
applyMiddleware(thunk)
);
import { createStore } from 'redux';
import thunk from 'redux-thunk';
import { INote } from '../common/types';
import reducer, { initialState } from './reducers';
export interface ApplicationState {
notes: INote[];
}
export default createStore(
reducer,
initialState as any,
applyMiddleware(thunk)
);
export interface INote extends IPureNote {
id: number;
randomAsyncNumber: number;
}
...
// Расширяет интерфейс для асинхронности
export interface RandomAsyncNumber {
randomAsyncNumber: number;
}
export type ExtendRandomNumber<T> = RandomAsyncNumber & T;
case ACTIONS.ADD_NOTE: {
const {
note: newPureNote,
randomAsyncNumber
} = payload as IAddNotePayload;
const id = Math.max(...notes.map((note: INote) => note.id)) + 1;
const newNote: INote = {
...newPureNote,
id
};
return { ...state, notes: [...notes, newNote] };
}
case ACTIONS.ADD_NOTE: {
const {
note: newPureNote,
randomAsyncNumber
} = payload as ExtendRandomNumber<IAddNotePayload>;
const id = Math.max(...notes.map((note: INote) => note.id)) + 1;
const newNote: INote = {
...newPureNote,
id,
randomAsyncNumber
};
return { ...state, notes: [...notes, newNote] };
}
case ACTIONS.ADD_NOTE: {
const {
note: newPureNote,
randomAsyncNumber
} = payload as ExtendRandomNumber<IAddNotePayload>;
const id = Math.max(...notes.map((note: INote) => note.id)) + 1;
const newNote: INote = {
...newPureNote,
id,
randomAsyncNumber
};
return { ...state, notes: [...notes, newNote] };
}
export const addNote = ({ note }: IAddNotePayload) => ({
type: ACTIONS.ADD_NOTE,
payload: {
note
}
});
export const addNoteRequest = ({ note }: IAddNotePayload) => {
return (dispatch: Dispatch) => {
setTimeout(() => {
const randomAsyncNumber = Math.ceil(Math.random() * 100);
dispatch(addNoteSuccess({ note, randomAsyncNumber }))
}, 3000)
}
}
export const addNoteSuccess = ({
note,
randomAsyncNumber
}: ExtendRandomNumber<IAddNotePayload>) => ({
type: ACTIONS.ADD_NOTE,
payload: { note, randomAsyncNumber }
});
export const addNoteRequest = ({ note }: IAddNotePayload) => {
return (dispatch: Dispatch) => {
setTimeout(() => {
const randomAsyncNumber = Math.ceil(Math.random() * 100);
dispatch(addNoteSuccess({ note, randomAsyncNumber }))
}, 3000)
}
}
export const addNoteSuccess = ({
note,
randomAsyncNumber
}: ExtendRandomNumber<IAddNotePayload>) => ({
type: ACTIONS.ADD_NOTE,
payload: { note, randomAsyncNumber }
});
export const addNoteRequest = ({ note }: IAddNotePayload) => {
return (dispatch: Dispatch) => {
setTimeout(() => {
const randomAsyncNumber = Math.ceil(Math.random() * 100);
dispatch(addNoteSuccess({ note, randomAsyncNumber }))
}, 3000)
}
}
export const addNoteSuccess = ({
note,
randomAsyncNumber
}: ExtendRandomNumber<IAddNotePayload>) => ({
type: ACTIONS.ADD_NOTE,
payload: { note, randomAsyncNumber }
});
export const addNoteRequest = ({ note }: IAddNotePayload) => {
return (dispatch: Dispatch) => {
setTimeout(() => {
const randomAsyncNumber = Math.ceil(Math.random() * 100);
dispatch(addNoteSuccess({ note, randomAsyncNumber }))
}, 3000)
}
}
export const addNoteSuccess = ({
note,
randomAsyncNumber
}: ExtendRandomNumber<IAddNotePayload>) => ({
type: ACTIONS.ADD_NOTE,
payload: { note, randomAsyncNumber }
});
export const addNoteRequest = ({ note }: IAddNotePayload) => {
return (dispatch: Dispatch) => {
setTimeout(() => {
const randomAsyncNumber = Math.ceil(Math.random() * 100);
dispatch(addNoteSuccess({ note, randomAsyncNumber }))
}, 3000)
}
}
export const addNoteSuccess = ({
note,
randomAsyncNumber
}: ExtendRandomNumber<IAddNotePayload>) => ({
type: ACTIONS.ADD_NOTE,
payload: { note, randomAsyncNumber }
});
const result: any = useSelector(
selector: Function,
equalityFn?: Function
);
function mapStateToProps(state: ApplicationState) {
const { notes } = state;
return {
notes
};
}
const notes: INote[] = useSelector(
(state: ApplicationState) => state.notes
);
const dispatch = useDispatch();
const dispatch = useDispatch();
const onClick = useCallback(() => {
...
dispatch(saveNote({ id, newNote }))
}, [dispatch])
const store = configureStore({
reducer,
middleware,
devTools: process.env.NODE_ENV !== 'production',
preloadedState,
enhancers: [reduxBatch]
});
const store = configureStore({ reducer });
function createSlice({
reducers: Object<string, ReducerFunction | ReducerAndPrepareObject>
initialState: any,
name: string,
extraReducers?:
| Object
| ((builder: ActionReducerMapBuilder) => void)
})
const notesReducer = (
state: ApplicationState = initialState,
action: IAction
) => {
const { type, payload } = action;
const { notes } = state;
switch (type) {
case ACTIONS.ADD_NOTE
...
default:
return state;
}
};
import { ..., ACTION } from '../common/types';
export const addNote = ({ note }: IAddNotePayload) => ({
...
});
export const editNote = ({ id, newNote }: IEditNotePayload) => ({
...
});
export const changeStatus = ({ id, newStatus }: IChangeStatusPayload) => ({
...
});
const notesStore = createSlice({
name: 'notes',
initialState,
reducers: {
addNote(state, { payload }: PayloadAction<IAddNotePayload>) {
...
state.notes.push(newNote); // Прямо мутируем стейт
},
...
}
});
export const { actions, reducer } = notesStore;
const notesStore = createSlice({
name: 'notes',
initialState,
reducers: {
addNote(state, { payload }: PayloadAction<IAddNotePayload>) {
...
state.notes.push(newNote); // Прямо мутируем стейт
},
...
}
});
export const { actions, reducer } = notesStore;
npm i redux react-redux @reduxjs/toolkit
const dispatch = useDispatch();
return useMemo(
() => bindActionCreators(action, dispatch),
[dispatch, action]
);