2017-02-06 19 views
2

Прошло больше недели, и я изо всех сил пытался заставить его работать.React Native: реквизит и состояние изменено, но не переработано

В нижеследующем коде данные поступают через реквизит (рисунок Редукса) и визуализируются, на самом деле есть оценки, виды форм. когда вы заполняете форму и отправляете ее, она отправляется, реквизит и изменения состояния. (эта форма будет удалена из состояния, реквизит), но форма все еще отображается в представлении. Вызов this.loadData(); в коде не помогает. но PullDownToRefresh работает и обновляет компонент. RefreshControl также звонит this.loadData();

Что я делаю неправильно? Любые решения, пожалуйста? Evaluation.js:

import React, {Component, PropTypes} from "react"; 
import { 
    ActivityIndicator, 
    Text, 
    View, 
    Image, 
    NetInfo, 
    Alert, 
    TouchableOpacity, 
    ScrollView, 
    TextInput, 
    Dimensions, 
    RefreshControl, 
    Platform 
} from 'react-native'; 
import { styles, moment, GoogleAnalytics, KeyboardAwareScrollView, DeviceInfo, Loader, Accordion, I18n, CustomNavBar, DatePicker, FMPicker, CustomStarRating, Icon, CustomPicker, CustomQuestion, CustomDatePicker } from "../../common/components"; 
let { width, height } = Dimensions.get('window'); 

var index = 0; 

export default class Evaluation extends Component { 
    static propTypes = { 
     user: PropTypes.string.isRequired, 
    users: PropTypes.object.isRequired, 
     evaluation: PropTypes.object.isRequired, 
    getEvaluation: PropTypes.func.isRequired, 
     submitEvaluation: PropTypes.func.isRequired 
    }; 

    constructor(props) { 
    super(props); 
    this.state = { 
      date: moment().format('DD-MM-YYYY'), 
      isRefreshing: false, 
      isLoading: true, 
      dsource: [] 
    }; 
     this.list = {}; 
    } 

    componentWillMount(){ 
     this.loadData(); 
    } 

    componentWillReceiveProps(nextProps){ 
     this.processData(); 
    } 

    componentDidMount(){ 
     NetInfo.isConnected.fetch().then(isConnected => { 
     this.setState({ 
     isConnected: isConnected 
     }); 
    }); 
    NetInfo.isConnected.addEventListener(
     'change', 
     isConnected => { 
     this.setState({ 
      isConnected: isConnected 
     }); 
     } 
    ); 
    } 

    randomNumber(){ 
    return ++index; 
    } 

    loadData(){ 
     this.props.getEvaluation(this.props.users); 
    } 

    processData(){ 
     let {user, evaluation} = this.props; 
     let data = evaluation[user]; 
     let dsource = []; 
     let list = {}; 
     if(data){ 
      this.setState({ 
       isLoading: true 
      }); 
      if(Object.keys(data).length > 0){ 
       Object.keys(data).forEach((e)=>{ 
        let currentEvaluation = data[e]; 
        let fields = []; 
        list[currentEvaluation.evaluationId] = {}; 
        if(currentEvaluation.hasOwnProperty('evaluationField')){ 
         if(currentEvaluation.evaluationField.length > 0){ 
          currentEvaluation.evaluationField.forEach((f)=>{ 
           fields.push({ 
            ...f, 
            value: '' 
           }); 
           list[currentEvaluation.evaluationId][f.field_name] = { 
            value: '', 
            required: f.required 
           }; 
          }); 
         } 
        } else { 
        } 
       dsource.push({ 
         id: currentEvaluation.evaluationId, 
         title: currentEvaluation.evaluationTitle, 
         expire: currentEvaluation.evaluationExpire, 
         image: currentEvaluation.evaluationImage, 
         fields: fields 
       }); 
      }); 
      } 
     } 
     this.list = list; 
     this.setState({ 
      dsource, 
      isLoading: false 
     }); 

    setTimeout(()=>{ 
     this.forceUpdate(); 
    }, 1000); 
    } 

    async getObjectToPost(evaluationID){ 
     let obj = this.list; 
    return this.list[evaluationID]; 
    } 

    async changeValue(a,b,c,type){ 
     let list = this.list; 
    if(type == 'date' || type == 'picker'){ 
     list[a][b].value = c; 
    } else { 
     let oldValue = this.getValue(a,b); 
     if(oldValue != c){ 
       list[a][b].value = c; 
      } 
    } 
     this.list = list; 
    } 

    getValue(id, name){ 
     let list = this.list; 
     return list[id][name].value; 
    } 

    async evaluationSubmit(evalid){ 
     const {user, users, evaluation, getEvaluation, submitEvaluation} = this.props; 
    let allRequiredEnetered = true; 
    let objToPost = {}; 
    let answers = await this.getObjectToPost(evalid); 
    for(let key in answers){ 
     objToPost[key]=answers[key].value; 
     if(answers[key].required == true && answers[key].value == ''){ 
     allRequiredEnetered = false; 
     } 
    } 
    if(allRequiredEnetered){ 

     objToPost = { 
     result: objToPost 
     }; 
     let stringifiedObject = JSON.stringify(objToPost); 

     if(this.state.isConnected){ 
       submitEvaluation(user, users, evalid, stringifiedObject,()=>{ 
        console.log('Running callback'); 
        Alert.alert(
         I18n.t("evaluation_submitted_title"), 
         I18n.t("evaluation_submitted_desc") 
        ); 
        setTimeout(()=>{ 
        this.loadData(); 
       }, 1000); 
       }); 
     } else { 
       //// Save evaluation to submit later. 
     Alert.alert(
      I18n.t("offline_mode_title"), 
      I18n.t("evaluation_offline") 
     ); 
     } 

    } else { 
     Alert.alert(
     I18n.t("invalid_input_title"), 
     I18n.t("please_fill_in") 
    ); 
    } 
    } 

    renderQuestions(EvaluationFields,TotalEvaluationsCount,EvaluationID){ 
    let tmdata = []; 
    for(let n=0; n < TotalEvaluationsCount; n++){ 
     if(n > 0){ 
     tmdata.push(
     <View key={this.randomNumber()} style={styles.separator}></View> 
     ); 
     } 
     tmdata.push(
     <Text key={this.randomNumber()} style={styles.questionTitle} >{EvaluationFields[n].label}{EvaluationFields[n].required > 0 ? ' *' : ''}{'\n'}</Text> 
    ); 
     switch (EvaluationFields[n].type) { 
     case 'date': 
     let currentValue = this.getValue(EvaluationID, EvaluationFields[n].field_name); 
     let dateToShow = this.props.date; 
     if(currentValue.length != undefined && currentValue.length != ''){ 
      dateToShow = currentValue; 
     } 
     tmdata.push(
      <View style={styles.datepicker} key={this.randomNumber()}> 
      <CustomDatePicker 
      mode="date" 
      placeholder={I18n.t("select_date")} 
      format="DD-MM-YYYY" 
      minDate="01-01-2000" 
      maxDate="01-01-2099" 
      showIcon={false} 
      confirmBtnText={I18n.t("confirm_button")} 
      cancelBtnText={I18n.t("login_page_scan_cancel")} 
      onDateChange={(date) => {this.changeValue(EvaluationID, EvaluationFields[n].field_name, date, 'date');}} 
      required={EvaluationFields[n].required > 0 ? true : false} 
      /> 
      </View> 
     ); 
     break; 
     case 'text': 
     tmdata.push(
      <TextInput 
      key={this.randomNumber()} 
      style={[styles.textinput, Platform.OS == "android" ? { borderWidth: 0, height: 35 } : {}]} 
      onChangeText={(text) => {this.changeValue(EvaluationID, EvaluationFields[n].field_name, text, 'text');}} 
      maxLength = {Number(EvaluationFields[n].max_length)} 
      autoCorrect={false} 
      autoCapitalize={'none'} 
      clearButtonMode={'always'} 
      placeholder={I18n.t("evaluations_comment_field")} 
      /> 
     ); 
     break; 
     case 'rate': 
     tmdata.push(
      <View key={this.randomNumber()} style={styles.starrating}> 
      <CustomStarRating 
       maxStars={Number(EvaluationFields[n].stars)} 
       rating={Number(this.getValue(EvaluationID, EvaluationFields[n].field_name))} 
       selectedStar={(rating) => {this.changeValue(EvaluationID, EvaluationFields[n].field_name, rating, 'rating');}} 
       starSize={(width/(Number(EvaluationFields[n].stars))) > (width/10) ? (width/10) : (width/(Number(EvaluationFields[n].stars)))} 
       required={EvaluationFields[n].required > 0 ? true : false} 
      /> 
      </View> 
     ); 
     break; 
     } 
     if(EvaluationFields[n].type == 'list'){ 
     if(EvaluationFields[n].widget == 'note'){ 
      tmdata.push(
      <View key={this.randomNumber()}> 
       <CustomQuestion 
        evaluationId={EvaluationID} 
        fieldName={EvaluationFields[n].field_name} 
        allowedValues={EvaluationFields[n].allowed_values} 
        noteColors={EvaluationFields[n].note_colors} 
        onChange={(value)=>{ this.changeValue(EvaluationID, EvaluationFields[n].field_name, value, 'custom') }} 
        required={EvaluationFields[n].required > 0 ? true : false} 
       /> 
      </View> 
     ); 
     } else { 
      let allowedValues = EvaluationFields[n].allowed_values; 
      let Options=[]; 
      let LabelsForOptions=[]; 

      for(let r=0; r < allowedValues.length; r++){ 
      Options.push(allowedValues[r][0]); 
      LabelsForOptions.push(allowedValues[r][1]); 
      } 
      tmdata.push(
      <View style={Platform.OS == "ios" ? styles.picker : styles.pickerSimple} key={this.randomNumber()}> 
       <CustomPicker 
       options={Options} 
       labels={LabelsForOptions} 
       onSubmit={(option) => {this.changeValue(EvaluationID, EvaluationFields[n].field_name, option, 'picker');}} 
       confirmBtnText={I18n.t("confirm_button")} 
       cancelBtnText={I18n.t("login_page_scan_cancel")} 
       text={I18n.t("please_select_answer")} 
       required={EvaluationFields[n].required > 0 ? true : false} 
       /> 
      </View> 
     ); 
     } 
     } 
    } 
    return(
     <View key={this.randomNumber()}>{tmdata}</View> 
    ); 
    } 

    render() { 
     let dsource = this.state.dsource; 
     return (
     <View style={styles.container}> 
      <View style={{ width: width, height: Platform.OS == "ios" ? 64 : 54}}> 
      <CustomNavBar 
       width={width} 
       height={Platform.OS == "ios" ? 64 : 54} 
       title={I18n.t("evaluation_page_nav_title")} 
       titleSize={18} 
       buttonSize={15} 
       background={"#00a2dd"} 
       color={"#FFF"} 
       rightIcon={"ios-person-outline"} 
       rightIconSize={30} 
       rightAction={()=> { this.props.openProfile(); }} 
      /> 
      </View> 
      <View style={{ height: Platform.OS == "ios" ? height - 114 : height - 130 }}> 
         {!this.state.isLoading ?<ScrollView 
         refreshControl={ 
          <RefreshControl 
           refreshing={this.state.isRefreshing} 
           onRefresh={this.loadData.bind(this)} 
           tintColor="#00a2dd" 
           title="" 
           titleColor="#00a2dd" 
           colors={['#00a2dd', '#00a2dd', '#00a2dd']} 
           progressBackgroundColor="#FFFFFF" 
          /> 
         } 
        > 
         {dsource.length > 0 ? 
          <View style={styles.container}> 
           <View> 
            <KeyboardAwareScrollView> 
             <View> 
              {dsource.map((data)=>{ 
               return(
                <View style={styles.cardContainer} key={this.randomNumber()}> 
                 <View style={styles.cardHeader} > 
                  <View style={styles.headerImageContainer}> 
                   <Image style={styles.headerImage} source={{uri: data.image}} /> 
                  </View> 
                  <View style={{ margin: 5 }}> 
                   <Text style={styles.cardTitle}>{data.title}</Text> 
                  </View> 
                 </View> 
                 <View style={{ padding: 5 }}> 
                  {this.renderQuestions(data.fields, data.fields.length, data.id)} 
                 </View> 
                 <View style={{ padding: 5 }}> 
                  <View style={styles.separator}></View> 
                  <Text style={styles.footerText}>{I18n.t("evaluations_mandatory")}{'\n'}{I18n.t("evaluations_desc_expire")} {data.expire}</Text> 
                  <TouchableOpacity onPress={() => this.evaluationSubmit(data.id)} style={styles.submitButton} > 
                   <Text style={styles.buttonText}>{I18n.t("evaluations_submit_button")}</Text> 
                  </TouchableOpacity> 
                 </View> 
                </View> 
               ); 
              })} 
             </View> 
            </KeyboardAwareScrollView> 
           </View> 
          </View> 
          : 
          <View style={styles.errorContainer}> 
           <View style={styles.error}> 
            <Text style={styles.Errortext}> 
             {I18n.t("evaluations_no_evaluation_available")} 
            </Text> 
           </View> 
          </View> 
         } 
        </ScrollView> 
        :<ActivityIndicator 
          animating={true} 
          style={{ paddingTop: Platform.OS == "ios" ? (height - 114)/2 : (height - 130)/2 }} 
          color={'#00a2dd'} 
          size={'small'} 
         />} 
      </View> 
     </View> 
    ); 
    } 
} 

EvaluationPage.js

import {bindActionCreators} from "redux"; 
 
import {connect} from "react-redux"; 
 
import Evaluation from "./components/Evaluation"; 
 
import {Actions as routes} from "react-native-router-flux"; 
 
import * as evaluationActions from "./evaluation.actions"; 
 

 
function mapStateToProps(state) { 
 
\t return { 
 
\t \t user: state.auth.user, 
 
\t \t users: state.auth.users, 
 
\t \t evaluation: state.evaluation.evaluation, 
 
\t \t openProfile: routes.profilePage 
 
\t } 
 
} 
 

 
function dispatchToProps(dispatch) { 
 
\t return bindActionCreators({ 
 
\t \t getEvaluation: evaluationActions.getEvaluation, 
 
\t \t submitEvaluation: evaluationActions.submitEvaluation 
 
\t }, dispatch); 
 
} 
 

 
export default connect(mapStateToProps, dispatchToProps)(Evaluation);

Evaluation.actions.js:

export const GET_EVALUATION = 'GET_EVALUATION'; 
 
export const GET_EVALUATION_FAILED = 'GET_EVALUATION_FAILED'; 
 
export const SUBMIT_EVALUATION = 'SUBMIT_EVALUATION'; 
 
export const SUBMIT_EVALUATION_FAILED = 'SUBMIT_EVALUATION_FAILED'; 
 

 
import Functions from '../common/Functions'; 
 

 
export const getEvaluation = (users) => { 
 
    return dispatch => { 
 
    Functions.getEvaluationsAPI(users) 
 
    .then((data)=>{ 
 
     const {evaluationsList} = data; 
 
     return dispatch(evaluationSuccess(evaluationsList)); 
 
    }) 
 
    .catch((e)=>{ 
 
     return dispatch(evaluationFailed(e)); 
 
    }); 
 
    }; 
 
} 
 

 
export const submitEvaluation = (user, users, evaluationId, evaluationData, callback) => { 
 
    return dispatch => { 
 
    Functions.submitEvaluation(user, users, evaluationId, evaluationData) 
 
    .then(()=>{ 
 
     console.log('Submit finished, getting evaluations'); 
 
     Functions.getEvaluationsAPI(users) 
 
     .then((data)=>{ 
 
     const {evaluationsList} = data; 
 
     console.log('Got evals list', evaluationsList); 
 
     return dispatch(evaluationSubmissionSuccess(evaluationsList)); 
 
     }) 
 
     .catch((e)=>{ 
 
     return dispatch(evaluationSubmissionFailed(e)); 
 
     }); 
 
    }) 
 
    .catch((e)=>{ 
 
     return dispatch(evaluationSubmissionFailed(e)); 
 
    }); 
 
    }; 
 
} 
 

 
const evaluationSuccess = (evaluationsList) => { 
 
    return { 
 
    type: GET_EVALUATION, 
 
    payload: { 
 
     evaluation: evaluationsList 
 
    } 
 
    } 
 
}; 
 

 
const evaluationFailed = (e) => { 
 
    return { 
 
    type: GET_EVALUATION_FAILED, 
 
    payload: { 
 
     error: e 
 
    } 
 
    } 
 
}; 
 

 
const evaluationSubmissionSuccess = (evaluationsList) => { 
 
    console.log('Submission success returning to reducer'); 
 
    return { 
 
    type: SUBMIT_EVALUATION, 
 
    payload: { 
 
     evaluation: evaluationsList 
 
    } 
 
    }; 
 
}; 
 

 
const evaluationSubmissionFailed = (e) => { 
 
    return { 
 
    type: SUBMIT_EVALUATION_FAILED, 
 
    payload: { 
 
     error: e 
 
    } 
 
    }; 
 
};

Evaluation.reducer.js:

import * as types from "./evaluation.actions"; 
 

 
export const INITIAL_STATE = { 
 
    evaluation: {} 
 
}; 
 

 
export default function evaluation(state = INITIAL_STATE, action){ 
 
    const {evaluation} = state; 
 
    switch(action.type){ 
 
    case types.GET_EVALUATION: 
 
    return Object.assign({}, state, { 
 
     evaluation: action.payload.evaluation 
 
\t \t }); 
 
    case types.GET_EVALUATION_FAILED: 
 
    return { 
 
     ...state, 
 
     evaluation 
 
    }; 
 
    case types.SUBMIT_EVALUATION: 
 
    let newObject = Object.assign({}, state, { 
 
     evaluation: action.payload.evaluation 
 
\t \t }); 
 
    return newObject; 
 
    case types.SUBMIT_EVALUATION_FAILED: 
 
    return { 
 
     ...state, 
 
     evaluation 
 
    }; 
 
    default: 
 
    return state; 
 
    } 
 
}

Store.js

import { persistStore, autoRehydrate } from "redux-persist"; 
import { combineReducers } from "redux"; 
import {REHYDRATE} from 'redux-persist/constants'; 
import { applyMiddleware, createStore, compose } from "redux"; 
import createActionBuffer from 'redux-action-buffer'; 
import { AsyncStorage } from "react-native"; 
import thunk from "redux-thunk"; 
import createLogger from "redux-logger"; 
import rootReducer from "./rootReducer"; 

const logger = createLogger(); 

const enhancer = compose(
    autoRehydrate(), 
    applyMiddleware(
    thunk, 
    logger, 
    createActionBuffer(REHYDRATE) 
) 
); 

const store = createStore(
    rootReducer, 
    {}, 
    enhancer 
); 

persistStore(store, {storage: AsyncStorage}); 

export default store; 

rootReducer.js

import { combineReducers } from "redux"; 
import auth from "./auth/auth.reducer"; 
import storage from "./storage/storage.reducer"; 
import courses from "./courses/courses.reducer"; 
import goals from "./goals/goals.reducer"; 
import evaluation from "./evaluation/evaluation.reducer"; 

const rootReducer = combineReducers({ 
    auth, 
    storage, 
    courses, 
    goals, 
    evaluation 
}); 

export default rootReducer; 

Root.js:

import React from "react"; 
import { View } from "react-native"; 
import { Provider } from "react-redux"; 
import store from "./store"; 
import Routes from "./Routes"; 

const Root =() => (
    <Provider store={store}> 
     <View style={{flex: 1}}> 
      <Routes /> 
     </View> 
    </Provider> 
); 

export default Root; 

ответ

1

только что нашел этот вопрос. на componentWillReceiveProps Я звонил this.processData(), а processData() получал данные от this.props, я должен был пройти nextProps до processData() и прочитать данные от nextProps.

componentWillReceiveProps(nextProps){ 
this.processData(nextProps); 
} 

processData(nextProps){ 
/// process data based on nextProps 
} 
1

Вам необходимо подключить компонент к магазину редукции, используя соединение.

Добавить импорт:

import {connect} from 'react-redux'; 

Изменить объявление класса:

class Evaluation extends Component {... 

А затем добавить подключенный экспорт в нижней части:

export default connect()(Evaluation); 
+0

Спасибо за ваш ответ. Я сделал то, что вы сказали, но ничего не изменил. – Ataomega

+0

Я обновил вопрос с остальной частью кода, если вы проверите EvaluationPage, у меня уже есть «connect». – Ataomega