2016-11-23 8 views
1

Wenn eine Liste von Benutzern vorhanden ist und jeder Eintrag einen Button »EDIT« hat. Wenn der Benutzer darauf klickt, geschieht folgendes:React/Redux-Individual state für jede Instanz einer Komponente

  1. Anfrage der Server für das Formular
  2. Komponente hinzufügen <UserEditForm /> dem Eintrag, was erweitert den Eintrag

Das bis auf eine Sache gut funktioniert: Wenn man auf weitere Schaltflächen klickt, erhält jede Instanz des Formulars die Daten des zuletzt angeforderten Benutzerformulars. Das liegt daran, dass ich nur eine userform Eigenschaft in dem Zustand habe.

Also, diese zu lösen ich userform zu userforms austauschen möchten, die sollten/ein Objekt wie das sein könnte:

userforms: { 
    <id of first instance>: { … }, //formdata 
    <id of second instance>: { … }, 
    … 
} 

Aber da ich bin neu in React/Redux Ich weiß nicht wirklich, wie das zu tun oder was der »richtige« Ansatz oder die beste Vorgehensweise ist, um es tatsächlich zu tun.

Meine Idee ist wie so eine höhere Ordnung Komponente zu erstellen:

import React from 'react'; 
import {connect} from 'react-redux'; 
import {uuid} from '../../helpers/uuid'; 

export const formdatainstance = (FormInstance) => { 

    let id = null; 

    class FormDataMapper extends React.Component { 
    constructor (props) { 
     super(props); 
     id = uuid(); 
    } 

    render() { 
     //extract the formdata from the state 
     //using the id 
     return <FormInstance { ...this.props } /> 
    } 
    } 

    const mapStateToProps = (state) => { 
    console.log(id); //is null for one run 
    return { 
     userforms: state.userforms 
    }; 
    }; 

    return connect(mapStateToProps)(FormDataMapper); 
} 

So in der List-Komponente ich kann:

import UserEditForm from './UserEditForm'; 
import {formdatainstance} from './formdatainstance'; 

const MappedUserEditForm = formdatainstance(UserEditForm); 

class List extends React.Component { 
    render(){ 
    return (
     {users.map(user => { 
     //more stuff 
     <MappedUserEditForm /> 
     //more stuff 
     })} 
    ); 
    } 
} 

Also meine Frage: Ist das eine gute Idee? Wenn ja, was wäre der richtige Weg, um die Bereinigung durchzuführen, wenn also im Lebenszyklus der Komponente sollte ich die Daten aus dem Zustand löschen? Gibt es eine andere Möglichkeit, das zu tun, die einfacher ist?

Danke für Hilfe!

+0

tun Sie mehrere Formulardaten behalten möchten (für jeder Benutzer) in dem Staat? Oder würde es ausreichen, dass Sie ein Zustandsobjekt für Formulardaten haben, das von einem Benutzer gefüllt und zurückgesetzt wird, wenn Sie für einen anderen Benutzer auf BEARBEITEN klicken? Könnten Sie auch relevanten Code von Ihrem Reducer posten? –

+0

Ich möchte eindeutige Formulardaten für jede Instanz eines gerenderten Formulars haben. Wenn also drei Benutzer in der Liste sind, möchte ich am Ende drei Formulare mit den Daten für jeden Benutzer anzeigen, die einzeln bearbeitet und eingereicht werden können. – philipp

+0

Ich wäre auch nett, diese Funktionalität zu abstrahieren, so dass sie auf andere Komponenten angewendet werden kann, die ein anderes Formular für andere Entitäten im System darstellen. – philipp

Antwort

1

Hier ist, was Sie tun können ...

import React from 'react'; 
import { compose } from 'redux'; 
import { connect } from 'react-redux'; 
import { reduxForm } from 'redux-form'; 

class UserEditForm extends Component { 
    ... 

    render() { 
     return <form onSubmit={this.props.handleSubmit(this.props.onSubmit)}> 
      ...form fields 
     </form> 
    } 
} 

const mapStateToProps = (state, ownProps) => { 
    return { 
     form: ownProps.formId 
    } 
} 

export default compose(
    connect(mapStateToProps), 
    reduxForm({ 
     //...other redux-form options 
    }) 
)(UserEditForm); 

Ihre ListComponent

render() { 
    return <ul> 
     {this.props.users.map(user => 
     <li key={user.id}> 
      ... 
      <UserEditForm formId={'form-' + user.id} onSubmit={...} /> 
     </li> 
    )} 
    </ul> 
} 

Auf diese Weise können Sie eine dynamische Form Namen haben.

+0

Danke für Ihre Antwort! Ich denke, ich werde redox Formen anschauen! Aber was du gepostet hast, scheint der Trick zu sein, werde es überprüfen ... – philipp

0

Auch wenn die Antwort von @jpdelatorre der beste Hit für mich zu sein scheint, da es auch den Link zu redux-forms enthält, was mir wahrscheinlich sehr helfen wird, würde ich gerne meine Arbeitslösung hier posten falls jemand es nützlich finden könnte. Es traf mich nur über Nacht, also musste ich testen, ob mein Gedanke richtig war, was ich schließlich beweisen konnte.

Ich war nicht in der Lage, die gesamte Mapping mit einem einzigen HOC zu tun und ich musste auch Reducer hinzufügen/ändern.Im Grunde funktioniert es so:

  1. Datenzuordnung wird von ID getan,

  2. die ursprünglichen Aktion Schöpfer eingewickelt werden, so dass die verwendete ID an das Objekt gebunden ist

  3. die Reduzierungen sind Zwei verpackt und mit dem »Datamap« -Reduzierer

Der Code der ursprünglichen Reducer und Action-Creators muss nicht geändert werden Was macht die Verpackung einfach zu bedienen? Ich wollte zuerst uuid 's verwenden, die im laufenden Betrieb erstellt werden, aber ich habe das verworfen, um den gesamten Anwendungszustand speichern und wiederherstellen zu können.

so der HOC-Code ist, dass:

import React from 'react'; 
import {connect} from 'react-redux'; 

// The Component to wrap, 
// all of its actions 
// its default state 
export const formdatainstance = (FormInstance, Actions, defaultState = {}) => { 

    const mapStateToProps = (state) => { 
    return { 
     mappedData: state.mappedData 
    }; 
    }; 

    class FormDataMapper extends React.Component { 
    static propTypes = { 
     id: React.PropTypes.string.isRequired 
    }; 

    static contextTypes = { 
     store: React.PropTypes.object 
    }; 

    //most of mapping happens here 
    render() { 
     //wrap the action creators 
     const actions = Object.keys(Actions).reduce((list, key) =>{ 
     list[key] = (...args) => { 
      const action = Actions[key](...args); 

      //handle asyn operations as well 
      if('then' in action && typeof action['then'] == 'function') { 
      action.then(data => { 
       //attaching the id 
       this.props.dispatch({...data, id: this.props.id}); 
      }); 
      } else { 
      //attach the id 
      this.context.store.dispatch({...action, id: this.props.id }); 
      } 
     }; 
     return list; 
     }, {}), 
     //there wont be any data at first, so the default state is handed 
     //over 
     mappedProps = this.props.mappedData.hasOwnProperty(this.props.id) ? 
      this.props.mappedData[this.props.id] : defaultState; 

     //merge the hotchpotch 
     let props = Object.assign({}, mappedProps, this.props, actions); 

     //clean up 
     delete props.id; 
     delete props.mappedData; 

     return <FormInstance { ...props } /> 
    } 
    } 

    return connect(mapStateToProps)(FormDataMapper); 
}; 

das Reduktionscode:

//hlper method 
export const createTypesToReducerMap = (types, reducer) => { 
    return Object.keys(types).reduce((map, key) => { 
    map[types[key]] = reducer; 
    return map; 
    }, {}); 
} 


export const createMappedReducer = (reducerMap, defaultState = {}) => { 
    const HANDLERS = reducerMap.reduce((handlers, typeMap) => { 
    return { ...handlers, ...typeMap }; 
    },{}); 

    return (state, action) => { 

    if (!action.hasOwnProperty('id')) { 
     if (state === undefined) return defaultState; 
     return state; 
    } 

    const reducer = HANDLERS.hasOwnProperty(action.type) ? 
      HANDLERS[action.type] : null; 

    let a = {...action}; 
    delete a.id; 


    return reducer !== null ? 
     Object.assign({}, state, { [action.id]: reducer(state[action.id], a)}) : 
     state; 
    } 
} 

und schließlich das Geschäft:

const userEditTypeReducerMap = createTypesToReducerMap(userEditTypes, userFormReducer); 


const reducer = combineReducers({ 
    … 
    mappedData: createMappedReducer(
    [userEditTypeReducerMap], {}) 
    … 
}); 


export default compose(
    applyMiddleware(
    thunk 
) 
)(createStore)(reducer, {}); 
Verwandte Themen