Render data từ mongodb trong redux
Chào các bạn, Mình đang gặp khó khăn trong việc hiển thị data (dùng axios fetching) từ mongodb trên redux, phần server mình đã setup xong. Mình đã sử dụng componentDidMount để xử lý bất đồng bộ giữa fetching và rendering từ store, nhưng khi chạy thì báo lỗi ở dòng "let listImage = this.props.cityList.map((i)..." báo lỗi là "this.props.cityList.map is not a function". Nếu mình thay dòng lệnh trong cityLine() bằng " console.log('city', this.props)" thì có kết quả trả về từ server. Mình loay hoay giải quyết mấy ngày ko xong, nhờ các bạn tư vấn giùm, cám ơn các bạn. Code như bên dưới:
import React, {Component} from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import {getCity} from '../actions/cityRead';
class DisplayCities extends React.Component {
componentDidMount() {
this.props.getCity()
}
cityLine() {
//console.log('city', this.props)
let listImage = this.props.cityList.map((i) =>{
return <img src={i.image} />;
});
return listImage;
}
render() {
return (
<div style={{marginTop: 10}}>
{this.cityLine()}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
cityList: state.cities
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({getCity: getCity}, dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(DisplayCities)
1 CÂU TRẢ LỜI
Hàm render của bạn sẽ được chạy trước khi componentDidMount()
chạy cho nên lúc này hàm render sẽ không hiểu cityList
của bạn là gì và báo lỗi lên. Cách xử lý là bạn có thể thêm biến vào redux store ví dụ nhự fetchCityListSuccess = false
. Sau này khi action gọi đến API của bạn thực hiện xong thì bạn đồng thời cập nhật lại fetchCityListSuccess = true
và bên giao diện cũng lấy biến này ra để check xem có nên hiển thị dữ liệu không. Cụ thể bên UI bạn sẽ sửa lại như này:
import React, {Component} from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import {getCity} from '../actions/cityRead';
class DisplayCities extends React.Component {
componentDidMount() {
this.props.getCity()
}
cityLine() {
//console.log('city', this.props)
let listImage = this.props.cityList.map((i) =>{
return <img src={i.image} />;
});
return listImage;
}
render() {
return (
<div style={{marginTop: 10}}>
{this.props.fetchCityListSuccess && this.cityLine()}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
cityList: state.cities,
fetchCityListSuccess: state.fetchCityListSuccess,
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({getCity: getCity}, dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(DisplayCities)
Cám ơn bạn Huy, Mình có khai 1 biến tương tự trong reducer như đoạn code bên dưới. Khi mình console.log('city', this.props) thì có trả về kết quả, giá trị fetched từ false thành true, chứng tỏ đã có giá trị trên store. Nhưng khi mình map() để lấy giá trị từ store xuống thì báo lỗi ko nhận ra cityList. Nếu mình làm thuần trong reactjs thì chạy tốt... nên làm mình bối rối, bạn có ví dụ nào giống mình thì share với, cám ơn bạn nha
P/s: sorry mọi người vì đoạn code dưới mình ctr-alt-c ko được
import {CREATE_CITIES, FETCH_CITIES, UPDATE_CITIES, DELETE_CITIES, } from '../actions/actionTypes'
const initialState = { fetched: false, create: false, delete: false, cities: [], city: { name: '', image:'' }, error: null };
const cityReducer = (state=initialState, action) =>{
switch (action.type){
case 'FETCH_CITIES':{
return {...state,
cities: action.payload,
fetched: true,
create: false,
delete: false,
error: null
}
}
case 'CREATE_CITIES': {
return {...state,
fetched: false,
create: true,
delete: false,
error: null,
city: {
name: '',
image:''
}
}
}
case 'UPDATE_CITIES':{
return {...state,
cities: [...state.cities, action.payload],
fetched: true,
create: false,
delete: false,
error: null
}
}
case 'DELETE_CITIES': {
const _id = action.payload.data._id;
return {...state,
fetched: false,
create: true,
delete: false,
error: null,
cities: state.cities.filter(item => item._id !== _id)
}
}case 'FETCH_CITIES_ERR':{
return {...state,
fetched: false,
create: false,
delete: false,
error: action.payload,
}
}
default:
return state;
}
}
export default cityReducer;
Trong phần render bạn thử thêm như mình ở trên xem
{this.props.fetched && this.cityLine()}
@HuyDQ amazing!! it worked, bạn giải thích lại cơ chế giùm mình với, có phải như bạn đã nói ở trên ko? Mình mới vào nghề nên còn hổng nhiều thứ quá
@BruceKieu như bạn trên đã nói rồi đó bạn ... bạn coi lại kĩ về life cycle sẽ hiểu rõ hơn ... gửi bạn link
@BruceKieu bạn hãy đọc kĩ lại phần life cycle của React để nắm rõ hơn nhé, như trong trường hợp của bạn thì bạn có thể hiểu như này:
- Hàm
render()
sẽ được chạy trước sau đó mới chạy đến hàmcomponentDidMount()
- Trong hàm
render()
của bạn lúc này gọi đếncityLine()
và cụ thể là gọi đếnthis.props.cityList
. Tuy nhiên do hàmcomponentDidMount()
chạy sau nên lúc này bạn thì props city list của bạn chưa có gì nên nó báo lỗi - Tuy nhiên nếu bạn thêm phần
{this.props.fetched && this.cityLine()}
thì ở lần chạy hàmrender()
đầu propsfetched
là false nên nó sẽ không gọi đến hàmcityLine()
mà trả về null - Sau đó đến lượt hàm
componentDidMount()
chạy và nó lấy đượccityList
về và đồng thờifetched
lúc này được đổi thành true - Do 2 props này thay đổi nên hàm
render()
sẽ được gọi lại và lúc này nó sẽ in ra kết quả mà bạn gọi từ API về
@HuyDQ Mình hiểu rồi, đưa {this.props.fetched} để lách lỗi, hay nhỉ. Sắp tới mình có thời gian khoảng 1 tháng ở HN, ko biết bạn có mở lớp học offline về MERN stack ko cho mình theo với
@dot.dot Cám ơn bạn Darkness nhé
Mình đang tạo 1 search filter sử dụng redux mà thấy bí quá. Có 1 ví dụ "https://www.youtube.com/watch?v=-evtGed_9Jg" làm từ backend nhưng theo các bạn có nên làm từ backend ko? Nếu có ví dụ nào share mình với nha, cám ơn nhiều nhiều
@BruceKieu tùy, vài chục vài trăm record thì tải hết về filter client nhưng vài ngàn vài chục ngàn thì phải làm ở server thôi.
@BruceKieu mình không mở lớp nhé bạn ). Còn phần filter thì bạn nên gửi request về server lấy giữ liệu hiển thị vì nếu bạn tải về hết client thì sau này khi giữ liệu nhiều lên sẽ xảy ra nhiều vấn đề khác dẫn đến phải sửa lại code
@Plumpboy bạn có ví dụ nào viết search filter bằng redux trên server với database là mongodb thì share mình với
@BruceKieu không quan trọng bạn db gì, quan trọng bạn dùng ngôn ngữ gì, ở Laravel thì bạn tham khảo https://viblo.asia/p/laravel-eloquent-technique-dedicated-query-string-filtering-oZVRg4XZMmg5
@BruceKieu filter bằng redux trên server ???
@Plumpboy ơi, trong ví dụ này https://www.youtube.com/watch?v=-evtGed_9Jg , mình thấy tác giả code trên backend (server.js) để nhận các string từ search bar và trả về kết quả sau khi đã filter. Sau đó chuyển qua frontend dùng redux viết các handleChange tương tác với store để nhận kết quả filter và hiển thị... Có 1 điều mình chưa hiểu (có lẽ do mình chưa học tới) là sau khi store tiếp nhận các state mới thì làm sao nó cập nhật dữ liệu lại server và gửi lên database (mongodb/firebase). Nếu như dùng thuần reactjs thì việc giao tiếp giữa client-server-database dễ hiểu hơn nhiều. Mình đang làm 1 project dùng MERN stack, phần backend + database (Mongodb, Mongoose, Express, Nodejs) và frontend (reactjs, axios) cơ bản xong, nhưng khi viết lại frontend bằng redux thì thấy lộn xộn quá. Laravel thì mình chưa đụng, nhìn code chóng mặt lun . Mình mới vô lập trình đc 5 tháng nên thấy cái j cũng mới, kiến thức cứ vụn vặt chưa kết nối được. Do đó mình đang cần tìm 1 khóa học cấp tốc về MERN ở HN trong T7, T8, các bạn có địa chỉ nào tin cậy thì share mình với nha, mình ko quan trọng chứng chỉ, chỉ cần kiến thức. Cám ơn các bạn nha
@BruceKieu redux là 1 state management, có thể hiểu là quản lý tất cả các biến trong 1 app js (không riêng gì reactjs, nó có thể dùng ở các thư viện, framework khác). "sau khi store tiếp nhận các state mới thì làm sao nó cập nhật dữ liệu lại server và gửi lên database". Có vẻ bạn chưa hiểu cách làm việc của 1 mern stack app. Lấy ví dụ cho bạn nhé:
Trong project của bạn sẽ có 2 app 1 là app chạy trên trình duyệt người dùng, sẽ được server gửi đến trình duyệt trong request đầu tiên. App này giao tiếp với người dùng xử lý những việc tương tác và hiển thị với người dùng, ở đây bạn dùng reactjs để làm nó. 1 app chạy trên server, để tương tác với database, xử lý các logic nghiệp vụ và trả về dữ liệu cần thiết cho app 1. 2 app này giao tiếp với nhau qua api.
Giả sử bạn có 1 web có chức năng bình luận, khi người dùng thêm 1 bình luận thì app sẽ xử lý thế này:
- Đầu tiên function addComment trong component Comment được gọi, nó dispatch action ADD_COMMENT đến Reducer, trong thời gian này bạn làm cái loading quay quay cho nó đẹp =))
- 1 request được gửi lên server (tùy vào logic trong reducer). Và bạn chỉ cần biết cái endpoint của api cần truyền gì truyền lên là được.
- Nếu request thành công, thì thêm comment vào store, comment sẽ hiện ra trên web, nếu thất bại thì hiển thị thông báo cho người dùng.
Ở Server thì nó qua route, middleware, controller, insert vào model rồi trả về response thôi
Mà 5 tháng bạn chơi ngay MERN không ổn đâu.
Cám ơn @Plumpboy đã giải thích, mình cũng dần dần hiểu ra rồi . Bạn nói đúng, mình cũng đang hộc máu vì thằng MERN này đây