2016-07-29 3 views
3

위젯 위젯 감속기를 작성하고 렌더 트리를 직렬로 반응시키는 방법을 알아 내는데 어려움을 겪고 있습니다. 결과적으로 반응 감속기를 사용하여 렌더러의 감속기를 렌더 트리의 소품에 매핑 할 수 있습니다.어떻게 반응 - redux와 소품에 redux 저장소에 캡슐화 된 UI 상태를 매핑 할 수 있습니까?

이와 같은 설정을 가정 해보십시오. ====

NameView.jsx: 
... 
render() { 
    return <div> Name: {this.props.name} </div>; 
} 
... 

====

NameAction.js: 
... 
export const CHANGE_NAME = 'CHANGE_NAME'; 
... 
export function changeNameAction(newName) { 
    return { 
    type: CHANGE_NAME, 
    payload: newName, 
    }; 
} 

====

NameReducer.js: 

import { CHANGE_NAME } from './NameAction'; 

function ui(state = {name: ''}, action) { 
    switch(action.type) { 
    case(CHANGE_NAME): 
     return Object.assign({}, state, {name: action.payload}); 
     break; 
    default: 
     return state; 
    } 
} 

export default ui; 

를 : 나는 어떤 응용 프로그램에서 어디서나 사용할 수있는 NameWidget를 만들기 위해 노력하고있어

NameWidget.js: 

import { connect } from 'react-redux'; 
import { NameView } from './NameView'; 

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

const NameWidget = connect(
    mapStateToProps 
)(NameView); 

export default NameWidget; 

직접 NameWidget을 사용하는 경우 probl em :

NameApp.jsx: 

import { createStore } from 'redux'; 
import app from './NameReducers'; 
let store = createStore(app); 
... 
function render() { 
    return (
    <Provider store={store}> 
     <NameWidget/> 
    </Provider> 
); 
} 

그러나이 모듈러를 만드는 방법은 없습니다. 나는이 위젯을 다른 어떤 것으로도 넣을 수 없다. 나는이하고 싶어한다고 가정

EncapsulatingView.jsx: 
... 
render() { 
    return (
    <div> 
     <NameWidget/> 
     <SomeOtherReduxWidget/> 
    </div> 
); 
} 
... 

====을

EncapsulatingReducer.js: 
import { combineReducers } from 'redux' 
import nameWidget from '../name/NameReducer'; 
import someOtherWidget from '../someOther/SomeOtherReduxWidgetReducer'; 

export default combineReducers({nameWidget, someOtherWidget}); 

(I 포함한 나머지 코드 (연결) 및 캡슐화에 대한 createStore는() * 분명 기대합니다.)

거의은 모든 캡슐화 된보기의 모든 작업이 고유 한 유형을 가지고있는 한 작동합니다. 하지만 문제는 NameWidget의 mapStateToProps입니다. 조상의 combineReducers()가 자신의 적 - 웅대 한 슈퍼 위젯과 애플리케이션을 정의하는 방법을 어떻게 든에 따라 자손을 -

... 
const mapStateToProps = (state) => { 
    return { 
    name: state.nameWidget.name, 
    }; 
}; 
... 

등등 : 그것은 가게의 섹션에 새 경로를 사용 위에서 변경해야 보정하기 위해 mapStateToProps()를 변경해야합니다. 이렇게하면 코드의 캡슐화와 재사용이 중단되고 반응을 줄이는 방법으로 코드를 처리하는 방법을 알 수 없습니다. combineReducers()를 작성하여 위젯을 정의한 다음 결과 저장소를 해당 위치의 소품으로 매핑하는 방법은 어디에서나 쓸 수 있습니다.

(아무 것도 제시하지 않고 반복 된 combineReducers()가 아래쪽 모양을 생성하지만 mapStateToProps()가 그 모양을 검색하기 위해 하향식 "절대 경로"접근 방식을 사용하는 것으로 보입니다.)

+0

당신이 수출을 계획하십니까

New NameWidget.js: const _ = require('lodash'); import { connect } from 'react-redux'; import { NameView } from './NameView'; const mapStateToProps = (state, props) => { const uiStore = ( (ownProps && _.has(ownProps, 'uiStorePath') && ownProps.uiStorePath && ownProps.uiStorePath.length) ? _.get(state, ownProps.uiStorePath) : // deep get...old versions of lodash would _.deepGet() state ); return { name: uiStore.name, }; }; const NameWidget = connect( mapStateToProps )(NameView); export default NameWidget; 

==== : 당신 EncapsulatingReducer.js에서 combineReducers() 기본적으로 때마다, 당신은 EncapsulatingView.js에 uiStorePath 소품을 통과 기억해야 코드를 다른 프로젝트에 추가하거나 동일한 프로젝트의 다른 설정에서 위젯을 다시 사용하려는 의도가 있습니까? – Gennon

+0

단기간은 프로젝트마다 다르지만, 좋은 패턴/해결책이 있다면 잘하면 두 가지를 모두 지원할 것입니다. – jdowdell

+0

정의 된 이름 (양식)을 자체 루트 감속기로 사용하는 [redux-form] (http://redux-form.com/5.3.1/#/getting-started) 모양이 있었습니까? 그런 식으로 구성 요소는 state.form에서 모든 값을 찾습니다. – Gennon

답변

1

흥미로운 질문입니다. 부모님에 의해 guid가 생성되고 소품을 통해 전달되도록 사용자의 목적에 부합하는지 궁금하다면 위젯의 해당 인스턴스에 대한 상태 객체의 인덱스로 간단히 사용하십시오. 따라서이 위젯의 ​​새로운 인스턴스를 만들 때마다 상위에 ID를 생성 한 다음이를 소품으로 전달해야하며 connect 메소드에서 mapStateToProps 및 mapDispatchToProps 둘 다에서 사용할 수 있습니다. . 나는 이론 상으로는이 부모 컴포넌트를 직접 만들 수도 있고 사용 중일 때 투명 할 수도 있고 componentDidMount를 사용하여 컴포넌트 상태로 저장하고 자식에게 전달할 새로운 GUID를 생성하기 만하면된다.

+0

감사합니다. 존! 비슷한 점을 생각해 봤지만 어떻게 소품을 전달할 지 모르겠습니다. 당신이 정교 할 수 있습니까? connect()는 본질적으로 render()가 아닌 반환하는 타입을 가져올 때 호출됩니다. 나는 함수에서 connect()를 랩핑 한 다음 render() 중에 동적으로 호출하여 그 함수가 전달한 ID를 전달할 수 있다고 생각한다. 하지만 난 동적으로 생성 된 유형의 모든 렌더링을 렌더링하는 의미에 대해 확신하지 않아요 ... – jdowdell

+0

그래서 당신은 부모 구성 요소를 가지고, 그리고 componentDidMount (사실 componentWillMount 아마도 더 나은 장소입니다) 당신이 본질적으로 것이라고 'this.setState ({childId : newGuid()})'를 호출 한 다음 render 메소드에서''와 같은 자식 컨테이너 컴포넌트를 렌더링한다. 컨테이너 구성 요소는 단순히 실제 구성 요소와'connect'를 호출 한 결과 인 'redux only'구성 요소를 의미합니다. – John

+0

그런 다음 연결 함수에서 mapStateToProps 및 mapDispatchToProps 함수 인 매개 변수를 전달할 때 _those_ 함수에서 두 번째 매개 변수 (구성 요소의 소품)를 사용하여 ID를 사용합니다. 예를 들어 연결 함수는 다음과 같습니다. https://jsbin.com/joyodaxazi/1/edit?js – John

0

John은 mapStateToProps()의 ownProps 함수 arg를 통해 저장소 "라우팅"로직을 전달하면서 그에 대한 올바른 매직을 제공했기 때문에 John에게이 질문에 대한 기여도를 보냈습니다. 그러나 나는 그것에 대한 내 자신의 회전을 선호.

EncapsulatingView.js: 

... 
render() { 
    const uiStorePathBase = ((this.props.uiStorePath &&   
     this.props.uiStorePath.length) ? 
    this.props.uiStorePath + '.' : 
    '' 
); 
    return (
    <div> 
     <NameWidget uiStorePath={uiStorePathBase+"nameWidget"}/> 
     <SomeOtherWidget uiStorePath={uiStorePathBase+"someOtherWidget"/> 
    </div> 
); 
} 
...