2017-11-18 3 views
1

이것은 약간의 longwinded 문제이며 해결할 두통의 톤을 제공합니다.여러 양식을 렌더링하는 구성 요소에서 상태를 사용하지 않고 onSubmit 양식에 입력 값을 전달하는 방법은 무엇입니까?

투표 앱을 만들고 있습니다. 이 페이지에는 투표 할 수있는 투표 목록이 있습니다. 각 폴링은 해당 폴링에 사용할 수있는 여러 옵션을 나타내는 입력 라디오 단추로 구성된 양식입니다.

이전에 내가 수행 한 작업은 구성 요소 상태로 선택한 옵션을 this.state.value에 저장 한 다음 양식을 제출할 때 작업 작성자에게 인수로 전달하는 것이 었습니다.

하나의 설문 조사 옵션을 클릭하고 다른 설문 조사에서 제출을 클릭하면 실제로 잘못된 설문 조사에 잘못된 옵션을 제출했습니다.

입력 값을 구성 요소 상태로 저장하지 않고 onSubmit 양식을 전달하는 방법이 있습니까?

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import * as actions from '../../actions'; 
import Loading from '../Loading'; 

class MyPolls extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     skip: 0, 
     isLoading: true, 
     isLoadingMore: false, 
     value: '' 
    }; 
    this.handleSubmit = this.handleSubmit.bind(this); 
    this.handleChange = this.handleChange.bind(this); 
    } 

    componentDidMount() { 
    this.props.fetchMyPolls(this.state.skip) 
     .then(() => { 
     setTimeout(() => { 
      this.setState({ 
      skip: this.state.skip + 4, 
      isLoading: false 
      }); 
     }, 1000); 
     }); 
    } 

    sumVotes(acc, cur) { 
    return acc.votes + cur.votes 
    } 

    loadMore(skip) { 
    this.setState({ isLoadingMore: true }); 

    setTimeout(() => { 
     this.props.fetchMyPolls(skip) 
     .then(() => { 
      const nextSkip = this.state.skip + 4; 
      this.setState({ 
      skip: nextSkip, 
      isLoadingMore: false 
      }); 
     }); 
    }, 1000); 
    } 

    handleSubmit(title, e) { 
    // console.log(e.target); 
    e.preventDefault(); 
    const vote = { 
     title, 
     option: this.state.value 
    }; 

    console.log(vote) 
    } 

    handleChange(event) { 
    this.setState({ value: event.target.value }); 
    } 

    renderPolls() { 
    return this.props.polls.map(poll => { 
     return (
     <div 
      className='card' 
      key={poll._id} 
      style={{ width: '350px', height: '400px' }}> 
      <div className='card-content'> 
      <span className='card-title'>{poll.title}</span> 
      <p> 
       Total votes: {poll.options.reduce((acc, cur) => { return acc + cur.votes }, 0)} 
      </p> 
      <form onSubmit={e => this.handleSubmit(poll.title, e)}> 
       {poll.options.map(option => { 
       return (
        <p key={option._id}> 
        <input 
         name={poll.title} 
         className='with-gap' 
         type='radio' 
         id={option._id} 
         value={option.option} 
         onChange={this.handleChange} 
        /> 
        <label htmlFor={option._id}> 
         {option.option} 
        </label> 
        </p> 
       ) 
       })} 

       <button 
       type='text' 
       className='activator teal btn waves-effect waves-light' 
       style={{ 
        position: 'absolute', 
        bottom: '10%', 
        transform: 'translateX(-50%)' 
       }} 
       > 
       Submit 
       <i className='material-icons right'> 
        send 
       </i> 
       </button> 
      </form> 
      </div> 
      <div className='card-reveal'> 
      <span className='card-title'>{poll.title} 
       <i className='material-icons right'>close</i> 
      </span> 
      <p> 
       dsfasfasdf 
      </p> 
      </div> 
     </div> 
    ) 
    }) 
    } 

    render() { 
    return (
     <div className='center-align container'> 
     <h2>My Polls</h2> 
     {this.state.isLoading ? <Loading size='big' /> : 
     <div 
      style={{ 
      display: 'flex', 
      flexWrap: 'wrap', 
      justifyContent: 'space-evenly', 
      alignItems: 'center', 
      alignContent: 'center' 
      }}> 
      {this.renderPolls()} 
     </div>} 
     <div className='row'> 
      {this.state.isLoadingMore ? <Loading size='small' /> : 
      <button 
      className='btn red lighten-2 wave-effect waves-light' onClick={() => this.loadMore(this.state.skip)}> 
      Load More 
      </button>} 
     </div> 
     </div> 

    ); 
    } 
} 

function mapStateToProps({ polls }) { 
    return { polls } 
} 

export default connect(mapStateToProps, actions)(MyPolls); 

앱 데모 : https://voting-app-drhectapus.herokuapp.com/ (사용 [email protected]과 암호 123 로그인하기)

Github에서의 환매 특약 : https://github.com/drhectapus/voting-app

내가 어떤 제안에 개방적이야. 감사!

+0

문제에 대한 일반적인 솔루션은 독립적 인'state'와 함께 (A''구성 요소 클래스를 생성하는 것' onSubmit()')을 호출하여 각'Poll'을 렌더링합니다. –

+0

내가 간과했던 쉬운 해결책이 있다는 것을 알았습니다. 감사 ! – doctopus

답변

1

"React'ish"패턴이 많을수록 더 많은 구성 요소로 분류 할 수 있습니다.
Poll은 구성 요소이고, PollOption도 구성 요소 일 수 있습니다.
각각은 내부적으로 상태를 처리 할 수 ​​있습니다.

App 또는 다른 모든 상태 관리자를 redux과 같이 유지할 수 있습니다.이 상태 관리자는 모든 설문 조사를 보유하고 각 사용자가 선택한 옵션 (id)을 참조 할 수 있습니다.

가리키는 또 다른 것은 각 render 호출에서 새로운 함수 참조를 전달하는 경향이 있다는 것입니다. 예를 들어
은 : 당신이 Reconciliation and The Diffing Algorithm of react을 방해 할 수 있기 때문에

onSubmit={e => this.handleSubmit(poll.title, e)} 

이것은 나쁜 관행으로 간주됩니다.

각각 소품이있는 콜백을 다시 실행할 수있는 구성 요소로 나누면이 방법으로 처리기를 전달할 필요가 없습니다. 여기

은 데이터와 작은 예입니다

const pollsFromServer = [ 
 
    { 
 
    _id: "5a0d308a70f4b10014994490", 
 
    title: "Cat or Dog", 
 
    _user: "59f21388843e737de3738a3a", 
 
    __v: 0, 
 
    dateCreated: "2017-11-16T06:30:34.855Z", 
 
    options: [ 
 
     { option: "Cat", _id: "5a0d308a70f4b10014994492", votes: 0 }, 
 
     { option: "Dog", _id: "5a0d308a70f4b10014994491", votes: 0 } 
 
    ] 
 
    }, 
 
    { 
 
    _id: "5a0c7941e655c22b8cce43d7", 
 
    title: "Blonde or Brunette?", 
 
    _user: "59f21388843e737de3738a3a", 
 
    __v: 0, 
 
    dateCreated: "2017-11-15T17:28:33.909Z", 
 
    options: [ 
 
     { option: "Blonde", _id: "5a0c7941e655c22b8cce43d9", votes: 0 }, 
 
     { option: "Brunette", _id: "5a0c7941e655c22b8cce43d8", votes: 0 } 
 
    ] 
 
    }, 
 
    { 
 
    _id: "5a0c7924e655c22b8cce43d4", 
 
    title: "Coke or Pepsi", 
 
    _user: "59f21388843e737de3738a3a", 
 
    __v: 0, 
 
    dateCreated: "2017-11-15T17:28:04.119Z", 
 
    options: [ 
 
     { option: "Coke", _id: "5a0c7924e655c22b8cce43d6", votes: 0 }, 
 
     { option: "Pepsi", _id: "5a0c7924e655c22b8cce43d5", votes: 0 } 
 
    ] 
 
    }, 
 
    { 
 
    _id: "5a0c78c2e655c22b8cce43d0", 
 
    title: "Favourite german car?", 
 
    _user: "59f21388843e737de3738a3a", 
 
    __v: 0, 
 
    dateCreated: "2017-11-15T17:26:26.724Z", 
 
    options: [ 
 
     { option: "BMW", _id: "5a0c78c2e655c22b8cce43d3", votes: 0 }, 
 
     { option: "Mercedes", _id: "5a0c78c2e655c22b8cce43d2", votes: 0 }, 
 
     { option: "Audi", _id: "5a0c78c2e655c22b8cce43d1", votes: 0 } 
 
    ] 
 
    } 
 
]; 
 

 
class Poll extends React.Component { 
 

 
    onSubmit = optionId => { 
 
    const { pollId, onSubmit } = this.props; 
 
    onSubmit(pollId, optionId); 
 
    }; 
 

 
    render() { 
 
    const { title, options, selectedOption } = this.props; 
 
    return (
 
     <div> 
 
     <h3>{title}</h3> 
 
     <ul> 
 
      {options.map((o, i) => { 
 
      return (
 
       <PollOption 
 
       isSelected={selectedOption === o._id} 
 
       onClick={this.onSubmit} 
 
       name={o.option} 
 
       optionId={o._id} 
 
       /> 
 
      ); 
 
      })} 
 
     </ul> 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
class PollOption extends React.Component { 
 
    onClick =() => { 
 
    const { optionId, onClick } = this.props; 
 
    onClick(optionId); 
 
    }; 
 

 
    render() { 
 
    const { name, isSelected } = this.props; 
 
    const selectedClass = isSelected ? "selected" : ''; 
 
    return (
 
     <li 
 
     className={`poll-option ${selectedClass}`} 
 
     onClick={this.onClick} 
 
     > 
 
     {name} 
 
     </li> 
 
    ); 
 
    } 
 
} 
 

 
class App extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     polls: pollsFromServer, 
 
     submittedPolls: [] 
 
    }; 
 
    } 
 

 
    onPollSubmit = (pollId, optionId) => { 
 
    this.setState({ 
 
     submittedPolls: { 
 
     ...this.state.submittedPolls, 
 
     [pollId]: optionId 
 
     } 
 
    }); 
 
    }; 
 

 
    render() { 
 
    const { polls, submittedPolls } = this.state; 
 
    return (
 
     <div> 
 
     {polls.map((p, i) => { 
 
      const selectedPoll = submittedPolls[p._id]; 
 
      return (
 
      <Poll 
 
       selectedOption={selectedPoll} 
 
       pollId={p._id} 
 
       onSubmit={this.onPollSubmit} 
 
       title={p.title} 
 
       options={p.options} 
 
      /> 
 
     ); 
 
     })} 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
ReactDOM.render(<App />, document.getElementById("root"));
.poll-option{ 
 
    cursor: pointer; 
 
    display: inline-block; 
 
    box-shadow: 0 0 1px 1px #333; 
 
    padding: 15px; 
 
} 
 
.selected{ 
 
    background-color: green; 
 
    color: #fff; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="root"></div>

+0

위대한 설명. 감사! – doctopus