Лучший способ передать значение из компонента в Sagate Redx компонента - PullRequest
0 голосов
/ 29 августа 2018

У меня есть вопрос о передаче значения (item.id) из одного компонента в сагу другого компонента, где я мог бы добавить дополнительное поле в теле POST и сделать запрос.

У меня есть два компонента: 1-й компонент формы, где два поля ввода. 2-й компонент - это Item, который получен из API. Итак, есть значение itemId, которое мне нужно дать при выполнении запроса POST с формой.

Мое решение сейчас состоит в том, чтобы передать itemId в localalstorage, а затем передать его в саге, но это вызывает некоторые ошибки, когда пользователь открывает два окна браузера. Что было бы лучшим решением для этой задачи?

Компонент My Item:

export class FindClientItem extends React.PureComponent {
  constructor() {
    super();

    this.state = {
      modalIsOpen: false,
    };

    this.openModal = this.openModal.bind(this);
    this.closeModal = this.closeModal.bind(this);
  }

  openModal() {
    this.setState({ modalIsOpen: true });
  }

  closeModal() {
    this.setState({ modalIsOpen: false });
    localStorage.removeItem('itemId');
  }

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

    if(this.state.modalIsOpen){
     localStorage.setItem('itemId',item.itemId);
    }

    // Put together the content of the repository
    const content = (
      <Wrapper>
        <h3>{item.title}</h3>
        Details: {item.description}...<button onClick={this.openModal}>
          More
        </button>
        <Modal
          isOpen={this.state.modalIsOpen}
          onRequestClose={this.closeModal}
          style={customStyles}
          contentLabel="Modal"
        >
          <h3>{item.title}</h3>
          Details: {item.description} <br />
          <button onClick={this.openBidModal}>Submit</button>{' '}
        </Modal>
      </Wrapper>
    );

    // Render the content into a list item
    return <ListItem key={`items-${item.itemId}`} item={content} />;
  }
}

А потом еще одна сага моего первого компонента формы:

export function* submitForm() {
  try {
    const formType = 'item';
    const body = yield select(makeSelectModifiedData());
    body.itemId = localStorage.getItem('itemId');
    let requestURL;

    switch (formType) {
      case 'item':
        requestURL = 'http://localhost:1234/item';
        break;
      default:
    }
    const response = yield call(request, requestURL, { method: 'POST', body });
  } catch (error) {
    Alert.error('Error message...', {
      html: false,
    });
  }
}

Ответы [ 3 ]

0 голосов
/ 29 августа 2018

index.js

import {handleSave, loadData } from './action';
import Modal from './Modal',

export class GetFormData extends React.PureComponent {

  componentDidMount() {
    this.props.loadData();
  }

  saveData = (data) => {
     this.props.handleSave(data)
  }

  render() {
    return (
      <div>

        <Modal
          isOpen={this.state.modalIsOpen}
          onRequestClose={this.closeModal}
          style={customStyles}
          contentLabel="Modal"
          data={this.props.getdata}
         handlePost={this.saveData}
        />
      </div>
    )
  }
}

const mapStateToProps = state => ({
  getdata: state.formData,
});

const mapDispatchToProps = dispatch => ({
  loadData: bindActionCreators(loadData, dispatch),
  handleSave: bindActionCreators(handleSave, dispatch),
});

export default connect(mapStateToProps, mapDispatchToProps)(GetFormData);

actions.js

import {
  LOAD_DATA,
  LOAD_DATA_SUCCESS,
  LOAD_DATA_FAILED
  HANDLE_SAVE,
  HANDLE_SAVE_SUCCESS,
  HANDLE_SAVE_FAILED
} from './constants';

export function loadData() {
  return {
    type: LOAD_DATA,
  };
}

export function loadDataSuccess(formData) {
  return {
    type: LOAD_DATA_SUCCESS,
    formData
  };
}

export function loadDataFailed(error) {
  return {
    type: LOAD_DATA_FAILED,
    error
  };
}

export function handleSave(data) {
  return {
    type: HANDLE_SAVE,
    data
  };
}

export function handleSaveSuccess() {
  return {
    type: HANDLE_SAVE_SUCCESS
  };
}

export function handleSaveFailed(error) {
  return {
    type: HANDLE_SAVE_FAILED,
    error
  };
}

reducers.js

import { fromJS } from 'immutable';

import {
  LOAD_DATA, LOAD_DATA_SUCCESS, LOAD_DATA_FAILED,
  HANDLE_SAVE,
  HANDLE_SAVE_SUCCESS,
  HANDLE_SAVE_FAILED
} from './constants';

const initialState = fromJS({
  formData: undefined,
});


function formDataReducer(state = initialState, action) {
  switch (action.type) {
    case LOAD_DATA:
      return state;

    case LOAD_DATA_SUCCESS:
      return state.set('formData', action.formData);

    case LOAD_DATA_FAILED:
      return state.set('errormsg', fromJS(action.errormsg));

    case HANDLE_SAVE:
      return state.set('data', action.data);

    case HANDLE_SAVE_SUCCESS:
      return state.set('message', action.message);

    case HANDLE_SAVE_FAILED:
      return state.set('errormsg', fromJS(action.errormsg));

    default:
      return state;
  }
}

saga.js

import { takeEvery, call, put } from 'redux-saga/effects';
import {
  LOAD_DATA,
  LOAD_DATA_SUCCESS,
  LOAD_DATA_FAILED,
  HANDLE_SAVE,
  HANDLE_SAVE_SUCCESS,
  HANDLE_SAVE_FAILED
} from './constants';


export function* getFormDataWorker() {
  try {
    const formData = yield call(api);
    if (formData) {
      yield put({ type: LOAD_DATA_SUCCESS, formData });
    }
  } catch (errormsg) {
    yield put({ type: LOAD_DATA_FAILED, errormsg });
  }
}

//  watcher
export function* formDataWatcher() {
  yield takeEvery(LOAD_DATA, getFormDataWorker);
}


export function* saveDataWorker(action) {
  try {
    const message = yield call(savedata, action.data);
    if (message) {
      yield put({ type: HANDLE_SAVE_SUCCESS, message });
    }
  } catch (errormsg) {
    yield put({ type: HANDLE_SAVE_FAILED, errormsg });
  }
}

//  watcher
export function* saveDataWatcher() {
  yield takeEvery(HANDLE_SAVE, saveDataWorker);
}


// All sagas to be loaded
export default [
  saveDataWatcher,
  formDataWatcher,
];

Modal.js

const Modal = ({data, handlePost}) => (
   { data ? data.map(item => (
      <input type="text" value={item.id} />
    )

   }
   <Button type="submit" onClick={handlePost}/ >

)

Надеюсь, это поможет!

0 голосов
/ 01 сентября 2018

Я бы предложил следующее:

  • Удалить использование localalstorage

  • Вкл. componentDidUpdate отправить действие, которое устанавливает itemId в хранилище Redux.

    componentDidUpdate() { this.props.setItemId({itemId: this.props.item.itemId}) }

  • При отправке формы отправьте то же действие, которое вы используете для запуска саги.

  • Измените селектор makeSelectModifiedData, чтобы вернуть itemId, который вы храните в Redux сейчас.

0 голосов
/ 29 августа 2018

Не уверен, что это «лучший» способ сделать это, однако, хорошо работает для меня. Вы пытались создать общий файл js (импортированный в оба компонента), который получает / устанавливает переменную? например.

shared.js

let data = null;

setData(d){
    data = d;
}

getData(){
    return data;
}

addChangeListner(eventName, callback){
    this.on(eventname, callback);
}

dispatcherCallback(action){
    switch(action.actionType){
         case 'SET_DATA':
         this.getData();
    }
}

Всякий раз, когда вам требуется обновить ваш компонент, вы можете добавить прослушиватель изменений, чтобы затем возвращать новые данные после установки, чтобы компоненты не были синхронизированы. Просто не забудьте удалить слушателя послесловия!

Компонент

componentDidMount(){
    shared.addChangeListner('SET_DATA', this.onUpdate)
}

// use x to pass to your saga...
onUpdate(){
    var x = shared.getData();
}

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...