Реагировать на Redux this.props пусто? - PullRequest
0 голосов
/ 09 ноября 2018

Я использую реактивную модель для моего проекта. У меня есть контейнер LoginForm, который аутентифицирует пользователя и сохраняет ответ от API в состоянии. Я хотел бы получить доступ к этому ответу из другого контейнера NavHeader, который является заголовком, и он должен отображать эту информацию.

this.props в NavHeader не определен. Может кто-нибудь указать мне, где я ошибся здесь.

ОБНОВЛЕНИЕ: я пытался переместить редуктор и действия в контейнер приложения (root), но все равно не повезло. Очевидно, я что-то не так делаю, и я не могу этого понять. любая помощь будет принята с благодарностью!

UserLoginForm контейнер

index.js

export class UserLoginForm extends Component {
  constructor(props) {
    super(props);
  }

onLoginSubmit(e) {
    e.preventDefault();
    const { email, password } = this.state;
    this.props.dispatch(authorize(email, password));
  }
  render() {
    return (
      <HeroBannerStyle>
          <form>
                <InputField name="email" />
                <InputField type="password" />
                <Button onClick={this.onLoginSubmit}/>
          </form>
      </HeroBannerStyle>
    );}}

const mapStateToProps = createStructuredSelector({
  userLoginForm: makeSelectUserLoginForm(),
}); 
==> This essentially does this: state.get('userLoginForm', initialState);

const withConnect = connect(mapStateToProps);
const withReducer = injectReducer({ key: 'userLoginForm', reducer });
const withSaga = injectSaga({ key: 'userLoginForm', saga });

export default compose(withReducer,withSaga,withConnect(UserLoginForm);

actions.js

export function authSuccess(payload) {
  return {
    type: AUTH_SUCCESS, payload: {user: payload},
  };
}

reducer.js

export const authorize = (email, password) => ({
  type: AUTH_REQUEST,
  payload: {email, password},
});
export const initialState = fromJS({
  user: null
});

const userLoginFormReducer = (state = initialState, { type, payload }) => {
  switch (type) {
    case AUTH_SUCCESS: {
      return {
        ...state,
        user: payload.data,
      };
    }
    default:
      return state;
  }
};

export default userLoginFormReducer;

saga.js

function* fetchUserReqSaga({ payload: { email, password } }) {
  try {
    const response = yield call(fetchUser, { email, password });
    yield put({ type: AUTH_SUCCESS, payload: response });
} catch (error) {}
}

function fetchUser({ email, password }) {
  return usersAPI.post('/login', {email, password,});
}

Контейнер NavHeader

index.js

class NavHeader extends Component {
  constructor(props) {
    super(props);
    }       
      componentDidMount() {
        console.log('this.props..', this.props);//THIS IS UNDEFINED
      }

      render() {
        return (
              <div>{this.props.user}</div> // THIS IS EMPTY
        );      
}}
    const mapStateToProps = state => {
      console.log(state); //THIS DOES NOT HAVE 'userLoginForm'
      return {
        user: state.get('userLoginForm')
      }
    };

    const withConnect = connect(mapStateToProps);
    const withReducer = injectReducer({ key: 'navHeader', reducer });
    const withSaga = injectSaga({ key: 'navHeader', saga });
    export default compose(withReducer,withSaga,withConnect)(NavHeader);

1 Ответ

0 голосов
/ 09 ноября 2018

Компоненты и (rootReducer, rootSaga) подключены к хранилищу, через которое поступают все действия и реквизиты. Вы можете отладить в браузере, чтобы увидеть, как идут данные.

Вот официальная документация. Это легко и довольно коротко, но важно понять все это редуктор, действие, подпорки. Также есть небольшой фрагмент кода, чтобы увидеть, как он работает.

Redux документы

Пример короткого притока

Также здесь выписка из аналогичного проекта. Добавлено еще несколько строк из точек разрыва.

UPD:

Он принимает данные от rootReducer, который подключен к хранилищу. Если в инициализирован хранилище и объединены все редукторы, то так называемый combReducers:

export interface RootState {
    books: BooksState;
    authors: AuthorsState;
}

const rootReducer: Reducer<RootState> = combineReducers<RootState>({  
    authors: authorReducer,
    books: booksReducer

})
export default rootReducer;

После того, как редуктор вернул полезную нагрузку (данные), он принимается селектором:

export const getData = (state: RootState) => state.books.data

и он используется в mapStateToProps, я использовал connect для вызова функции высокого порядка и сбора данных из хранилища и создания контейнера. Compose не является излишним, и если вы используете его, вы должны проверить порядок ваших промежуточных программ (compose (m1, m2, m3 ...) справа налево):

const mapStateToProps = (state: RootState) => ({
  books: getData(state), 
  pagination: getPagination(state),
  loading: getLoadingStatus(state),
  error: getError(state),

})

    export default connect(mapStateToProps, { loadBooks, searchBook, removeBook, addBook,  editBook, sortBook, 
    })(FilterableBooksTable);

Затем речь идет о «умном» компоненте:

export interface BooksTableProps {
    readonly books: Array<Book>;
    loadBooks: (pagination: Pagination) => object; 
}

export interface BookFormProps {
    addBook: (name: string, author: string, cost: number, genre: string) => object;
}

type FilterableBooksTableProps = BooksTableProps & BookFormProps;

export default class FilterableBooksTable extends React.Component<FilterableBooksTableProps> {

render() {
  const {
    books,
    loadBooks,
    addBook,                   
  } = this.props

  return (        
      <div>
          <Row>
            <Col span={4}>
              <BookForm
                addBook={addBook}                    
                >
            </Col>
            <Col span={16}>
              <BookTable        
                books={books}
                loadBooks={loadBooks}            
              />
            </Col>                
          </Row>
      </div>        
  )
  }

И, наконец, данные доходят до «тупого» компонента:

render() {
   const {
       books                
   } = this.props;

  return (
    <div>           
      <Table          
        dataSource={books}          
        ...
      />
    </div>                
  )
}

Я не знаю, как настроен ваш магазин, поэтому я добавлю мой со всеми сагами, редукторами, подключенными к нему:

import { Store, createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer, { RootState } from '@redux/rootReducer';
import rootSaga from '@redux/sagas';

export default function configureStore(initialState?: RootState): Store<RootState> {
  const sagaMiddleware = createSagaMiddleware();
  const middlewares = [sagaMiddleware];

  const composeEnhancers = composeWithDevTools({});

  const enhancer = composeEnhancers(
    applyMiddleware(...middlewares)
  );

  const store = createStore(
    rootReducer,
    initialState!,
    enhancer,
  );

  if (module.hot) {
    module.hot.accept('@redux/rootReducer', () => {
      const nextRootReducer = require('@redux/rootReducer').default;
      store.replaceReducer(nextRootReducer);
    });
  }

  sagaMiddleware.run(rootSaga);

  return store;
}
...