I had asked this question before.
I looked carefully at the exchange section, which I advised, and I think there is no problem with the exchange section.
At least in my opinion there is no problem and I hardly know the cause of the problem.
And I was so frustrated that I put everything in the code.
If anyone can provide us with a clue to this problem, please reply to me.
interactions.js
import Web3 from 'web3'
import {
web3Loaded,
web3AccountLoaded,
tokenLoaded,
exchangeLoaded,
cancelledOrdersLoaded
} from './actions'
import Token from '../abis/Token.json'
import Exchange from '../abis/Exchange.json'
export const loadWeb3 = (dispatch) => {
const web3 = new Web3(Web3.givenProvider || 'http://localhost:7545')
dispatch(web3Loaded(web3))
return web3
}
export const loadAccount = async (web3, dispatch) => {
const accounts = await web3.eth.getAccounts()
const account = accounts[0]
dispatch(web3AccountLoaded(account))
return account
}
export const loadToken = async (web3, networkId, dispatch) => {
try {
const token = new web3.eth.Contract(Token.abi, Token.networks[networkId].address)
dispatch(tokenLoaded(token))
return token
} catch (error) {
console.log('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
export const loadExchange = async (web3, networkId, dispatch) => {
try {
const exchange = new web3.eth.Contract(Exchange.abi, Exchange.networks[networkId].address)
dispatch(exchangeLoaded(exchange))
return exchange
} catch (error) {
console.log('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
export const loadAllOrders = async (exchange, dispatch) => {
// if (exchange) { // Make sure exchange has been defined
// const exchange = new web3.eth.Contract(Exchange.abi, Exchange.networks[networkId].address)
const cancelStream = await exchange.getPastEvents('Cancel', { fromBlock: 0, toBlock: 'latest' })
// // await loadAllOrders(this.props.exchange, dispatch)
console.log(cancelStream)
}
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Navbar from './Navbar'
import Web3 from 'web3';
import Content from './Content'
import { connect } from 'react-redux'
// import Token from '../abis/Token.json'
import {
loadWeb3,
loadAccount,
loadToken,
loadExchange
} from '../store/interactions'
import { contractsLoadedSelector } from '../store/selectors'
class App extends Component {
componentWillMount() {
this.loadBlockchainData(this.props.dispatch)
}
async loadBlockchainData(dispatch) {
const web3 = loadWeb3(dispatch)
const network = await web3.eth.net.getNetworkType()
const networkId = await web3.eth.net.getId()
const accounts = await loadAccount(web3, dispatch)
const token = await loadToken(web3, networkId, dispatch)
if(!token) {
window.alert('Token smart contract not detected on the current network. Please select another network with Metamask.')
return
}
const exchange = await loadExchange(web3, networkId, dispatch)
if(!exchange) {
window.alert('Exchange smart contract not detected on the current network. Please select another network with Metamask.')
return
}
}
render() {
return (
<div>
<Navbar />
{ this.props.contractsLoaded ? <Content /> : <div className="content"></div> }
</div>
);
}
}
function mapStateToProps(state) {
return {
contractsLoaded: contractsLoadedSelector(state)
}
}
export default connect(mapStateToProps)(App);
reducers.js
import { combineReducers } from 'redux';
function web3(state={}, action) {
switch (action.type) {
case 'WEB3_LOADED':
return { ...state, connection: action.connection }
case 'WEB3_ACCOUNT_LOADED':
return { ...state, account: action.account }
default:
return state
}
}
function token(state = {}, action) {
switch (action.type) {
case 'TOKEN_LOADED':
return { ...state, loaded: true, contract: action.contract }
default:
return state
}
}
function exchange(state = {}, action) {
switch (action.type) {
case 'EXCHANGE_LOADED':
return { ...state, loaded: true, contract: action.contract }
case 'CANCELLED_ORDERS_LOADED':
return { ...state, cancelledOrders: { loaded: true, data: action.cancelledOrders } }
// case 'FILLED_ORDERS_LOADED':
// return { ...state, filledOrders: { loaded: true, data: action.filledOrders } }
// case 'ALL_ORDERS_LOADED':
// return { ...state, allOrders: { loaded: true, data: action.allOrders } }
default:
return state
}
}
const rootReducer = combineReducers({
web3,
token,
exchange
})
export default rootReducer
Content.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { exchangeSelector } from '../store/selectors'
import { loadAllOrders } from '../store/interactions'
class Content extends Component {
componentWillMount() {
this.loadBlockchainData(this.props.dispatch)
}
// async loadBlockchainData(exchange, dispatch) {
async loadBlockchainData(dispatch) {
await loadAllOrders(this.props.exchange, dispatch)
// this.loadBlockchainData(this.props.exchange)
// await loadAllOrders(exchange, dispatch)
}
function mapStateToProps(state) {
return {
exchange: state.exchangeSelector
}
}
export default connect(mapStateToProps)(Content)
selectors.js
import { get } from 'lodash'
import { createSelector } from 'reselect'
const account = state => get(state, 'web3.account')
export const accountSelector = createSelector(account, a => a)
const tokenLoaded = state => get(state, 'token.loaded', false)
export const tokenLoadedSelector = createSelector(tokenLoaded, tl => tl)
const exchangeLoaded = state => get(state, 'exchange.loaded', false)
export const exchangeLoadedSelector = createSelector(exchangeLoaded, el => el)
const exchange = state => get(state, 'exchange.contract')
export const exchangeSelector = createSelector(exchange, e => e)
export const contractsLoadedSelector = createSelector(
tokenLoaded,
exchangeLoaded,
(tl, el) => (tl && el)
)
Check exchange to make sure not undefined
export const loadAllOrders = async (exchange, dispatch) => {
const cancelStream = exchange ?
await exchange.getPastEvents('Cancel', { fromBlock: 0, toBlock: 'latest' })
: null // Check if exchange defined then call getPastEvents
console.log(cancelStream)
}
Related
In my backend, I use the post request type to fetch the data, so I can send a query or any other information I want in the body, so that the data is fetched on its basis
On the front end, I use React with Saga, and I can fetch data from the server without any problem
The case in which I need help is as follows.
I have a table containing products in the database and I want to divide these products into three pages based on a field in the table
Of course, I was able to do the filtering process in Saga as follows, and there is no problem
How can I pass this query in the image variable according to my need?
Suppose I want to create three pages in React, and for each page I will send a different filter, how do I do that?
I will attach the full code that I tried to do
Waiting for your help
this action
import {
GET_SERVICES_SUPPORT_LIST,
API_RESPONSE_SUCCESS,
API_RESPONSE_ERROR,
} from "./actionType";
// common success
export const ServicesSupportApiResponseSuccess = (actionType, data) => ({
type: API_RESPONSE_SUCCESS,
payload: { actionType, data },
});
// common error
export const ServicesSupportApiResponseError = (actionType, error) => ({
type: API_RESPONSE_ERROR,
payload: { actionType, error },
});
export const getServicesSupportList = services => ({
type: GET_SERVICES_SUPPORT_LIST,
payload: services,
});
this action type
// Actions
export const API_RESPONSE_SUCCESS = "API_RESPONSE_SUCCESS";
export const API_RESPONSE_ERROR = "API_RESPONSE_ERROR";
export const GET_SERVICES_SUPPORT_LIST = "GET_SERVICES_SUPPORT_LIST";
this saga
import { call, put, takeEvery, all, fork } from "redux-saga/effects";
import { toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import {
GET_SERVICES_SUPPORT_LIST,
} from "./actionType";
import {
ServicesSupportApiResponseSuccess,
ServicesSupportApiResponseError
} from "./action";
//Include Both Helper File with needed methods
import {
getServicesSupportList as getServicesSupportApi
}
from "../../helpers/backend_helper";
function* getServicesSupport({ payload: services }) {
try {
const response = yield call(getServicesSupportApi, services);
yield put(ServicesSupportApiResponseSuccess(GET_SERVICES_SUPPORT_LIST, response.data));
} catch (error) {
yield put(ServicesSupportApiResponseError(GET_SERVICES_SUPPORT_LIST, error));
}
}
export function* watchGetServicesSupportList() {
yield takeEvery(GET_SERVICES_SUPPORT_LIST, getServicesSupport);
}
function* servicesSupportSaga() {
yield all(
[
fork(watchGetServicesSupportList),
]
);
}
export default servicesSupportSaga;
this hook
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux'
import { getServicesSupportList} from "../../../store/actions";
const AllServicesSupportHook = () => {
const dispatch = useDispatch();
//to get state from redux
const { servicesSupportList, loder,error} = useSelector((state) => ({
servicesSupportList: state.ServicesSupport.servicesSupportList,
loder: state.ServicesSupport.loder,
error: state.ServicesSupport.error,
}));
//when first load
useEffect(() => {
if (loder) {
dispatch(getServicesSupportList());
}
}, [dispatch]);
let test ;
try {
if (servicesSupportList.paginator)
test = {query: {categoryTickets : 2} //This is definitely wrong
} catch (e) { }
const getPage = (services) => {
dispatch(getServicesSupportList(services));
}
return [servicesSupportList, loder,error,getPage]
};
export default AllServicesSupportHook;
get list
export const getServicesSupportList = (services) => api.create(url.GET_SERVICES_SUPPORT_LIST,services);
this reducer
import {
GET_SERVICES_SUPPORT_LIST,
API_RESPONSE_SUCCESS,
API_RESPONSE_ERROR,
} from "./actionType";
const INIT_STATE = {
servicesSupportList: [],
loder: true
};
const ServicesSupport = (state = INIT_STATE, action) => {
switch (action.type) {
case API_RESPONSE_SUCCESS:
switch (action.payload.actionType) {
case GET_SERVICES_SUPPORT_LIST:
return {
...state,
servicesSupportList: action.payload.data,
loder: false,
};
default:
return { ...state };
}
case API_RESPONSE_ERROR:
switch (action.payload.actionType) {
case GET_SERVICES_SUPPORT_LIST:
return {
...state,
error: action.payload.error,
loder: true,
};
default:
return { ...state };
}
case GET_SERVICES_SUPPORT_LIST: {
return {
...state,
loder: false,
};
}
default:
return { ...state };
}
};
export default ServicesSupport;
this components
import React from "react";
import { Row, Container ,Alert} from "reactstrap";
import ServicesSupportListItems from "./ServicesSupportListCard";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import Loader from "../../Common/Loader";
const ServicesSupportList = ({ data, loder, error }) => {
return (
<Container fluid={true}>
<Row>
{loder === false ? (
data.data ? (
data.data.map((item, index) => {
return (
<ServicesSupportListItems
key={index}
id={item.id}
categoryTickets={item.categoryTickets}
title={item.titleProduct}
description={item.description}
point={item.point}
/>
);
})
) : (<Alert color="danger"> {error} </Alert>)
) : ( <Loader error={error} />
)}
<ToastContainer closeButton={false} />
</Row>
</Container>
);
};
export default ServicesSupportList;
I found the solution, thank you
function* getServicesSupport({ payload: services }) {
try {
var response;
if (services === "Support") {
response = yield call(getServicesSupportApi,{query: {categoryTickets : 2}});
}
if (services === "CardFree") {
response = yield call(getServicesSupportApi,{query: {categoryTickets : 6}});
}
yield put(ServicesSupportApiResponseSuccess(GET_SERVICES_SUPPORT_LIST, response.data));
} catch (error) {
yield put(ServicesSupportApiResponseError(GET_SERVICES_SUPPORT_LIST, error));
}
}
I'm working on my first app. I put response from the server in an empty array in the state, but when I try to work with this array it throws undefined. On the first render everything seems OK but any futher manipulations fail. Please, help. I'm desperate here. My code:
App component:
import { React, useEffect, useContext } from "react";
import { getExchangeCourse } from "./api/currencyApi";
import { ADD_CURRENCY } from "./reducer/currencyReducer";
import { CurrenciesConverterContextComponent } from "./context/Context";
import Header from "./components/Header";
function App() {
const [, dispatch] = useContext(CurrenciesConverterContextComponent);
useEffect(() => {
getExchangeCourse().then(data => dispatch({
type: ADD_CURRENCY,
payload: data
}))
}, [])
return (
<div className="App">
<Header />
</div>
);
}
Header component:
export default function Header() {
const [{currencies}] = useContext(CurrenciesConverterContextComponent);
let USD = currencies.find(e => e.cc === "USD");
let EUR = currencies.find(e => e.cc === "EUR");
let GBP = currencies.find(e => e.cc === "GBP");
**these functions above work on a first render and then fail**
return (
<div className='converter-header'>
<span>{USD.cc} : {USD.rate}</span>
<span>{EUR.cc} : {EUR.rate}</span>
<span>{GBP.cc} : {GBP.rate}</span>
</div>
)
}
Reducer:
export const initialState = {
currencies: [],
}
export const ADD_CURRENCY = '[CURRENCIES] Add Currency';
export const currenciesReducer = ( state = initialState, action) => {
switch(action.type) {
case ADD_CURRENCY:
return {
...state,
// currencies: [...state.currencies, action.payload]
currencies: action.payload
};
default: {
return {
...state
}
}
}
}
API request:
import axios from 'axios';
const currencyAPI = axios.create({
baseURL: 'https://bank.gov.ua/NBUStatService/v1/statdirectory/exchange?json',
headers: {"Content-type": "application/json"},
})
export async function getExchangeCourse() {
const {data} = await currencyAPI.get()
console.log(data);
return data;
}
I am a newbie in React and Next JS, I want to set initial auth user data on initial load from the __app.js. But using dispatch throwing error "Invalid hook call". I know according to docs calling hooks in render function is wrong. but I am looking for an alternate solution to this.
How I can set auth data one-time so that will be available for all the pages and components.
I am including my code below.
/contexts/app.js
import { useReducer, useContext, createContext } from 'react'
const AppStateContext = createContext()
const AppDispatchContext = createContext()
const reducer = (state, action) => {
switch (action.type) {
case 'SET_AUTH': {
return state = action.payload
}
default: {
throw new Error(`Unknown action: ${action.type}`)
}
}
}
export const AppProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, {})
return (
<AppDispatchContext.Provider value={dispatch}>
<AppStateContext.Provider value={state}>
{children}
</AppStateContext.Provider>
</AppDispatchContext.Provider>
)
}
export const useAuth = () => useContext(AppStateContext)
export const useDispatchAuth = () => useContext(AppDispatchContext)
/_app.js
import 'bootstrap/dist/css/bootstrap.min.css'
import '../styles/globals.css'
import App from 'next/app'
import Layout from '../components/Layout'
import { mutate } from 'swr'
import { getUser } from '../requests/userApi'
import { AppProvider, useDispatchAuth } from '../contexts/app'
class MyApp extends App {
render() {
const dispatchAuth = useDispatchAuth()
const { Component, pageProps, props } = this.props
// Set initial user data
const setInitialUserData = async () => {
if (props.isServer) {
const initialData = {
loading: false,
loggedIn: (props.user) ? true : false,
user: props.user
}
const auth = await mutate('api-user', initialData, false)
dispatchAuth({
type: 'SET_AUTH',
payload: auth
})
}
}
//----------------------
// Set initial user data
setInitialUserData()
//----------------------
return (
<AppProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</AppProvider>
)
}
}
MyApp.getInitialProps = async (appContext) => {
let isServer = (appContext.ctx.req) ? true : false
let user = null
let userTypes = {}
// Get user server side
if (isServer) {
await getUser()
.then(response => {
let data = response.data
if (data.status == true) {
// Set user
user = data.data.user
userTypes = data.data.user_types
//---------
}
})
.catch(error => {
//
})
}
//---------------------
return {
props: {
user,
userTypes,
isServer
}
}
}
export default MyApp
I believe this is the intended use of the useEffect hook with an empty array as its second argument:
https://reactjs.org/docs/hooks-effect.html
import {useEffect} from 'react'
class MyApp extends App {
useEffect(()=> {
setInitialUserData()
},[])
render() {
...
}
}
The Redux Update operations I made on the client-side in Next JS are not updated in the server store.
Hello. I have a problem. I'm developing an SSR application with Next JS. I have provided the next js link with the next-redux-wrapper. State update operations can be provided. State updates I made on the server-side can be viewed on the client-side. The redux updates I made on the client-side also appear on the client-side, but when I refresh the page, it returns to the previous position. Sample scenario:
Users have addresses. Their addresses can be taken from the DB and printed on the screen. DB updates when I add a new address or delete the old address. Along with it, it is updated in the store on the client-side. So far there is no problem. However, when I refresh the page, for example, if there are 4 addresses before updating and I deleted one, after the refresh, it is printed as 4 addresses again. It continues like this until I get data from the server again.
How can I move the client-side store updates to the server-side without having to make requests to the server over and over again?
store.js
// store.js
import { createStore, applyMiddleware } from 'redux';
import { createWrapper } from "next-redux-wrapper";
import thunkMiddleware from 'redux-thunk'
// ROOT REDUCERS
import rootReducer from "../reducers";
const bindMiddleware = (middleware) => {
if (process.env.NODE_ENV !== 'production') {
const { composeWithDevTools } = require('redux-devtools-extension')
return composeWithDevTools(applyMiddleware(...middleware))
}
return applyMiddleware(...middleware)
}
const store_ = (initialState) => {
return createStore(rootReducer, initialState, bindMiddleware([thunkMiddleware]));
}
const wrapper = createWrapper(store_/*, { debug: true }*/);
export {
wrapper
}
_app.js
// _app.js
const MyApp = ({props, Component, pageProps }) => {
const store = useStore();
if (!store.getState().R_PageSettings.initStore)
{
store.dispatch({
type: HYDRATE,
payload: {
...props.initialState
}
})
}
return (
<>
<Head>
<title>{ variables.meta.title }</title>
</Head>
<Component {...pageProps} />
</>
)
}
const wrappedApp = wrapper.withRedux(MyApp);
export default wrappedApp;
wrappedApp.getInitialProps = async ctx => {
const data = await wrapper.getServerSideProps(
async (req) => {
const { store, ctx } = req;
const reduxStates = store.getState();
let user = reduxStates.R_User.user;
if (!user)
{
const cookies = parseCookies(ctx);
if (cookies.usr && user !== undefined)
{
const getUser = await CustomersController.tokenLoginControl(cookies.usr);
if (getUser && getUser.status)
{
store.dispatch(setUserSSR(getUser.user))
user = getUser.user;
}
else
destroyCookie(ctx, 'usr');
}
}
return {
user
}
}
)(ctx)
return data;
}
action.js
// CONSTANTS
import {
C_User
} from "../constants";
export const setUserSSR = user => {
return {
type: C_User.SET_USER,
payload: {
user
}
}
}
export const setUser = user => dispatch => {
return dispatch({
type: C_User.SET_USER,
payload: {
user
}
})
}
addresspage.js
// addresspage.js
import { connect } from 'react-redux';
import { bindActionCreators } from "redux";
// COMPONENTS
import UserPageLayout from "../UserPagesLayout";
import {
CustomerAddressForm
} from "../../../components";
// CONTROLLERS
import {
CustomersController
} from "../../../controllers";
// ACTIONS
import {
setUser
} from "../../../actions";
const MyAddressPage = connect(({ R_User }) => {
return {
R_User
}
}, dispatch => {
return {
setUser: bindActionCreators(setUser, dispatch)
}
})((props) => {
const addAddressHandle = () => {
props.fullBarOpen(
<CustomerAddressForm confirmHandle={async (address, setLoading) => {
const execute = await CustomersController.addAddress(address);
if (execute.status)
{
await props.setUser(execute.user);
}
else
{
setLoading(false);
}
}}
/>
);
}
return (
<UserPageLayout>
</UserPageLayout>
);
})
export default MyAddressPage;
I'v tried so many way to fetch data only once before rendering but have some issue:
1) I Can't call dispatch in componentDidMount because there is the rule that I can do it in Functional component only
2) If I try to call fetch function in the beginning of a Functional component it starts to rerender infinitely because fetch function calls every time and change a state in a redux store
3) I found a solution with useEffect but it generate exception "Invalid hook call" like in first point
How can I call fetch function only once in this component?
here is my component:
import React, { useEffect } from "react";
import { useParams as params} from "react-router-dom";
import { VolunteerCardList } from "./VolunteerCardList";
import { AnimalNeeds } from "./AnimalNeeds";
import { AppState } from "../reducers/rootReducer";
import { connect } from "react-redux";
import { Page404 } from "./404";
import { fetchAnimal } from "../actions/animalAction";
import { Dispatch } from "redux";
import { IAnimalCard } from "../interfaces/Interfaces";
const AnimalCard: React.FC<Props> = ({animal, loading, fetch}) => {
useEffect(() => {
fetch(); //invalid hook call????
}, [])
return (
<div className="container">
some html
</div>
)
}
interface RouteParams {
shelterid: string,
animalid: string,
}
interface mapStateToPropsType {
animal: IAnimalCard,
loading : boolean
}
const mapStateToProps = (state: AppState) : mapStateToPropsType=> {
return{
animal: state.animals.animal,
loading: state.app.loading
}
}
interface mapDispatchToPropsType {
fetch: () => void;
}
const mapDispatchToProps = (dispatch: Dispatch<any>) : mapDispatchToPropsType => ({
fetch : () => {
const route = params<RouteParams>();
dispatch(fetchAnimal(route.shelterid, route.animalid));
}
})
type Props = ReturnType<typeof mapStateToProps> & ReturnType<typeof mapDispatchToProps>;
export default connect(mapStateToProps, mapDispatchToProps as any)(AnimalCard);
this is my reducer:
export const animalReducer = (state: AnimalReducerType = initState, action: IAction) => {
switch (action.type) {
case AnimalTypes.FETCH_ANIMAL:
return {...state, animal: action.payload};
break;
default:
return state;
break;
}
this is action:
export interface IFetchAnimalAction {
type: AnimalTypes.FETCH_ANIMAL,
payload: IAnimalCard
}
export type IAction = IFetchAnimalAction;
export const fetchAnimal = (shelterId : string, animalId: string) => {
return async (dispatch: Dispatch) => {
const response = await fetch(`https://localhost:44300/api/animals/${animalId}`);
const json = await response.json();
dispatch<IFetchAnimalAction>({type: AnimalTypes.FETCH_ANIMAL, payload: json})
}
}
This runs as old lifecycle method componentDidMount:
useEffect(() => {
fetch(); //invalid hook call????
}, [])
I guess the behaviour you want to replicate is the one iterated by componentWillMount, which you cannot do by any of the standard hooks. My go-to solution for this is to let the acquire some loadingState, most explicitly as:
const AnimalCard: React.FC<Props> = ({animal, loading, fetch}) => {
const [isLoading, setIsLoading] = useState<boolean>(false);
useEffect(() => {
fetch().then(res => {
// Do whatever with res
setIsLoading(true);
}
}, [])
if(!isLoading){
return null
}
return (
<div className="container">
some html
</div>
)
}