I have a jobs list. I have to retrieve a job details by passing 'jobid' as a paramater using axios. i have created action and reducer for that and connect to that my component. api is getting called but in jobid it is showing undefined. I think it is route problem. Please suggest me where to defined that and how to get the details.
My api is like(ex: 'http://localhost:3000/app/jobs/87938'). Here jobid is 87938. There are multiple job with different job id in my job list. Problem is how to define the jobid and passing to the api to retrieve the details of job
action code:
export const retrieveLocations = (jobId) => (dispatch) => {
axios.get(retrieveUrl+'/jobs/'+jobId).then(res => {
dispatch({
type: RETRIEVE_LOCATION,
payload: res.data.job.basicDetails
});
});
};
reducer code:
case 'RETRIEVE_LOCATION':
return{
...state,
conLocations:action.payload
}
component code:
class ConfiguredLocation extends React.Component{
constructor(props){
super(props);
this.handleRemove = this.handleRemove.bind(this);
this.clearall = this.clearall.bind(this);
}
handleRemove(mruCode){
this.props.removeLocation(mruCode)
}
clearall (){
this.props.removeAllLocation()
}
componentDidUpdate(prevProps){
let currJobId = this.props.match.params.jobId;
let prevJobId = prevProps.match.params.jobId;
if(currJobId!==prevJobId){
this.props.retrieveLocations(jobId);
}
}
componentDidMount(){
let {jobId} = this.props.match.params;
this.props.retrieveLocations(jobId);
}
render(){
const _labels = store.getLabels();
const {conLocations} = this.props;
return(
<div className="col-padding">
<div className="pos-div"><h3>Configured Location</h3><button className="allLargeBtn" onClick={()=>{this.clearall()}}>Remove all location</button></div><hr/>
<table className="table">
<tbody>
{conLocations.map((loct,index)=><tr key={index}>
<td><h5>{loct.mruCode} - {_labels[loct.division]} - {loct.country}</h5></td>
<td className="text-right"><img alt="DeleteIcon" onClick={()=>this.handleRemove(loct.mruCode)}className="deleteIconStyle" src="img/delete_large_active.png" /></td>
</tr>
)}
</tbody>
</table>
</div>
);
}
}
const mapStateToProps = state =>{
return {
conLocations: state.locationRed.conLocations
};
};
const mapDispatchToProps = (dispatch) =>{
return{
removeLocation: (mruCode)=>{dispatch(removeLocation(mruCode))},
removeAllLocation: () =>{dispatch(removeAllLocation())},
retrieveLocations:(jobId) =>{dispatch(retrieveLocations(jobId))}
};
};
export default connect(mapStateToProps,mapDispatchToProps)(withRouter(ConfiguredLocation));
router code(appnavigator - i am not able to define job id here. Please suggest me on this)
import React from 'react';
import ReactDOM from 'react-dom';
import {Router, Route} from 'react-router-dom';
import { Security, ImplicitCallback, SecureRoute } from '#okta/okta-react';
import history from '../history';
import store from '../stores/store';
import ConfiguredLocation from '../components/location/ConfiguredLocation';
class AppNavigator extends React.Component {
constructor( props ) {
super( props );
this.state = {
loading: true
};
}
componentDidMount() {
var self = this;
setTimeout(() => {
self.setState({ loading: false });
}, 1000);
}
render() {
if (this.state.loading) {
return (
<div className="fix"><i className="fa fa-2x fa-circle fa-spin"></i>
<div>Loading</div>
</div>
)
} else {
return (
<Router history={history}>
<Security issuer={Something..}
client_id={something...}
redirect_uri={window.location.origin + '/app/callback'}
scope={['profile', 'openid']}>
<Route path='/callback' component={ImplicitCallback} />
<AppFrame />
</Security>
<Route exact path= '/jobs/:jobId' component={ConfiguredLocation}
</Router>
);
}
}
};
store code:(where appnavigator called)
<Provider store={createStoreWithMiddleware(reducers)}>
<AppNavigator />
</Provider>
Everything is working fine. If i call the api without parameter. it is working fine. So i am not able to route the parameter properly. Please help me on this.
l.png
All your code is correct after editing. When you want to generate dynamic route, like jobId in /app/jobs/87938 route, first you should write this route in router file like this:
<Route exact path="/app/jobs/:jobId" component={ConfiguredLocation}/>
after that, When open http://localhost:3000/app/jobs/87938 route your jobId is 87938 and you can get it in your componentDidMount lifecycle:
componentDidMount() {
const {jobId} = this.props.match.params;
this.props.retrieveLocations(jobId);
}
Demo:
Related
I'm trying to memorize some values in a react component because it's re rendering even when data hasn't changed (and wont change). Using useEffect + useState the data displays correctly, but the functions are triggered each time the component is re rendered. Currently am trying to implement the useMemo hook but the async call/promise is not resolving in the render process, so it doesn't even loads the data. I'll try to give the most information out of this:
This is my AppRouter component, i create the contract and pass it as value to a provider that will be used in some other components:
import { useWeb3React } from "#web3-react/core";
import React, { useEffect, useState } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { AdminScreen } from "../components/admin/AdminScreen";
import { ContractsContext } from "../components/ContractsContext";
import { Navbar } from "../components/ui/Navbar";
import { getLibrary } from "../helpers/web3Getters";
import { useCreateContract, useGetLibrary } from "../hooks.js/contractsHooks";
import { createContract } from "../web3-utils/contractCreation";
import { MarketRoutes } from "./MarketRoutes";
import { PrivateRoute } from "./PrivateRoute";
export const AppRouter = () => {
const context = useWeb3React();
//console.log("[1] context in app router: ", context);
const { contract: kolorTokenContract, loading: loadingContract } =
useCreateContract(
context,
"0x9414f981a5B5ef2bE455f2427E2166c35e8989fB",
"abis/KolorToken.json"
);
return (
//<p>{loadingLibrary ? "library ready" : "loading library"}</p>
<ContractsContext.Provider value={[kolorTokenContract]}>
<BrowserRouter>
<Navbar />
{/* Set private route for Admining nfts & tokens */}
<Routes>
<Route
path="/admin"
element={
<PrivateRoute>
<AdminScreen />
</PrivateRoute>
}
/>
<Route path="/*" element={<MarketRoutes />} />
</Routes>
</BrowserRouter>
</ContractsContext.Provider>
);
};
The contract is then obtained from my custom context in the admin route (which is what im testing now) and then passed to one of its children:
import React, { memo, useContext, useMemo } from "react";
import { getERC20Info } from "../../helpers/tokenGetters";
import { useGetERC20Info } from "../../hooks.js/contractsHooks";
import { ContractsContext } from "../ContractsContext";
export const TokenInfo = memo((tokenContract) => {
//const { _address: ERC20Address } = tokenContract;
const { address, owner, vault, supply } = useGetERC20Info(tokenContract);
//const result = useMemo(() => getERC20Info(tokenContract), [tokenContract]);
//console.log("contract from tokeninfo:", tokenContract);
//console.log("result: ", result);
return (
<div className="row align-items-center">
<div className="col-8 col-md-6 col-sm-4 ">Minting Form</div>
<div className="col-4 col-md-3 col-sm-2 animate__animated animate__fadeInRightBig">
<h2>Kolor Token Info</h2>
<p>
Address: <b>{address}</b>
</p>
<p>
Owner: <b>{owner}</b>
</p>
<p>
Vault: <b>{vault}</b>
</p>
<p>
Current supply: <b>{supply}</b>
</p>
</div>
<hr />
</div>
);
});
Actually i'm using a custom hook with useState and useEffect to fetch the data, but it re renders the TokenInfo component even when the tokenContract hasn't changed at all. This is my custom hook:
export const useGetERC20Info = (contract) => {
//console.log("contract from usegeterc20info effect: ", contract);
const [state, setState] = useState({
address: "loading...",
owner: "loading...",
vault: "loading...",
supply: "loading",
});
useEffect(() => {
getERC20Info(contract).then(({ address, owner, vault, supply }) => {
setState({
address,
owner,
vault,
supply,
});
return () => {
setState({});
};
});
}, [contract]);
return state;
};
My getERC20Info function, tries to fetch data from the blockchain, nothing wrong with that, its working fine:
export const getERC20Info = async (contract) => {
console.log("getting erc20 info...");
console.log("contract from geterc20info: ", contract);
const { _address: address } = contract;
const owner = await getERC20Owner(contract);
const vault = await getERC20Vault(contract);
const supply = await getERC20Supply(contract);
//console.log("supply: ", supply);
return {
address,
owner,
vault,
supply,
};
};
Thanks in advance for any help!
I'm trying to do something like this;
I have a file called /components/master_layout.js and it has the following content:
import useUser from "../data/use-user";
function MasterLayout({ children }) {
const { data, error, mutate } = useUser();
if ( error ) return <div>error</div>
if ( !data && !error ) return <div>loading..</div>
return (
<div>
{children}
</div>
)
}
export default MasterLayout
In short, this layout file returns according to the response of the useuser function.
Here is an example of a page where I use this layout:
file path and name: /pages/dashboard/index.js
import MasterLayout from "../../components/master_layout";
function Dashboard() {
return (
<MasterLayout>
dashboard..
</MasterLayout>
)
}
export default Dashboard
Can I use useUser data from Layout in '/pages/dashboard/index.js' and my other pages?
The reason I want this is, I'm trying to do something like:
import MasterLayout from "../../components/master_layout";
function Dashboard({data}) {
return (
<MasterLayout>
Welcome back, {data.username}
</MasterLayout>
)
}
export default Dashboard
Do I have any other choice but to pull the useUser for each page one by one and transfer it to the master layout as
You can use HOC pattern in this case. Something like
// with-data.js
import React from "react";
import useUser from "../data/use-user";
const withData = (WrappedComponent) => {
class WithData extends React.Component {
constructor(props) {
super(props);
this.state = {
data: "",
};
}
componentDidMount() {
const { data, error, mutate } = useUser();
this.setState({data:data});
}
render() {
const { data, ...otherProps } = this.props;
return (
<WrappedComponent data={this.state.data}/>
)
//* See how we can enhance the functionality of the wrapped component
}
}
return WithData;
};
export default withData;
Now you can use the withData,
import MasterLayout from "../../components/master_layout";
import withData from "../withData.js"
function Dashboard({data}) {
return (
<MasterLayout>
Welcome back, {data.username}
</MasterLayout>
)
}
export default withData(Dashboard);
In fact wrapping around any component with withData, can access the data variable.
I'm trying to update my home componentstate by getting data from the redux store every time the store is updated. I'm not sure what's wrong with the code below. I can't listen to store changes in my `home component.
my dispatch function is handled in this class.
export class GanttFilter extends Component {
...
handleSubmit = () => {
this.gFilter.filterGanttData(this.formValues)
.then((result) => {
if (result.data)
this.props.dispatch(ganttActions.loadGanttData(result.data));
});
}
...
GanttFilter.propTypes = {
dispatch: PropTypes.func.IsRequired
};
function mapStateToProps(state) {
return {
ganttData: state.gantt.ganttData
};
}
export default connect(mapStateToProps)(GanttFilter);
What I would like to do every time dispatch is called and the data changes, is update the state in my home component. Here is the component.
export class Home extends Component {
constructor() {
super();
this.state = {
data: [],
links: []
};
}
render() {
return (
<div className="fill">
<Gantt data={this.state.data} links={this.state.links} />
</div>
);
}
}
Home.propTypes = {
data: PropTypes.IsRequired
};
function mapStateToProps(state) {
return {
data: state.gantt.ganttData
};
}
export default connect(mapStateToProps)(Home);
the function mapStateToProps is never hit when I set a break point. How can I listen to changes to the store from the home component and update state?
Edit: Here is the wrapper component
function renderApp() {
// This code starts up the React app when it runs in a browser. It sets up the routing
// configuration and injects the app into a DOM element.
const baseUrl = document.getElementsByTagName("base")[0].getAttribute("href");
ReactDOM.render(
<ReduxProvider store={store}>
<AppContainer>
<BrowserRouter children={routes} basename={baseUrl} />
</AppContainer>
</ReduxProvider>,
document.getElementById("react-app")
);
}
reducers
const actionTypes = require('../actions/actionTypes');
const gantt = {
ganttData: [],
selectedTask: null
};
export default function ganttReducer(state = gantt, action) {
switch (action.type) {
case actionTypes.loadGanttData:
return { ...state, ganttData: [...action.ganttData] };
default:
return state;
}
}
root reducer
import { combineReducers } from 'redux';
import gantt from './ganttReducer';
const rootReducer = combineReducers({
gantt
});
export default rootReducer;
actions
const actionTypes = require('./actionTypes');
export function loadGanttData(ganttData) {
return { type: actionTypes.loadGanttData, ganttData };
}
export function getSelectedTask(ganttTask) {
return { type: actionTypes.setSelectedTask, ganttTask };
}
Error:
Make sure you import your Home component using import Home from '...' as opposed to import { Home } from '...', otherwise you'd be grabbing the unconnected component. In general, I would also avoid exporting the unconnected component.
Change this:
render() {
return (
<div className="fill">
<Gantt data={this.state.data} links={this.state.links} />
</div>
);
}
To
render() {
return (
<div className="fill">
<Gantt data={this.props.data} links={this.state.links} />
</div>
);
}
Your data is comming from your props (redux), not from your state.
I'm making a markdown editor using Marked library like this <div id="preview" dangerouslySetInnerHTML={ {__html: marked('Rendered by **marked**.''></div> but get TypeError: Object(...) is not a function.
Found two relevant posts on SO; first and second I'm using the same syntax as the answers but I get a TypeError. In both posts they used ReactDOM.render() method in the end. Full code:
import React, { Component } from 'react';
import './App.css';
import { Provider, connect } from 'react-redux';
import { createStore } from'redux';
import { marked } from "marked";
// Redux
const ADD = "ADD";
const addText = (text) => {
return {
type: ADD,
text: text
}
};
const textReducer = (state = {text: ''}, action) => {
switch(action.type) {
case ADD:
return Object.assign({},state, { text: action.text })
default:
return state
}
};
const store = createStore(textReducer);
// React
class App extends Component {
constructor(props){
super(props)
/*this.state = {
input : ''
}*/
this.handleChange = this.handleChange.bind(this);
};
handleChange(e){
/*this.setState({
input: e.target.value
})*/
this.props.addText(e.target.value)
};
render(){
return(
<div className="App-header">
<textarea id="editor" value={this.props.text} onChange={this.handleChange}></textarea>
<div id="preview" dangerouslySetInnerHTML={ {__html: marked('Rendered by **marked**.') } }></div>
</div>
)
}
};
// React-Redux
const mapStateToProps = (state) => {
return {
text: state.text
}
};
const mapDispatchToProps = (dispatch) => {
return {
addText: (text) => {
dispatch(addText(text))
}
}
};
const Container = connect(mapStateToProps, mapDispatchToProps)(App);
// eslint-disable-next-line
export default class AppWrapper extends Component {
render() {
return(
<Provider store={store}>
<Container />
</Provider>
);
}
};
The markdown text suppose to be rendered as html in preview element but instead I get TypeError: Object(...) is not a function.
UPDATE: apparently redux was not setup properly and was set to an array instead of object. I fixed that but I still get the same error.
I found the solution, problem was I imported marked as named import {import {marked} from 'marked' instead of import as default like this import marked from 'marked'
React Redux: Works Perfect with Sample A Code but returns dispatch error with sample B Code
Am trying to display Post records and then send/post back the records to server backend via onclick function.
To this effect, I have created two samples of Codes A & B.
Sample A codes works perfects but sample B Code works partly.
In sample code A below. Everything works fine as expected as I can display records and post back to server backend.
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { Actions } from '../_actions';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
this.props.dispatch(userActions.getRec());
}
handlePostId(postid,post_content){
//return (e) => this.props.dispatch(Actions.sendData(postid,post_content));
return this.props.dispatch(Actions.sendData(postid,post_content));
}
render() {
const { post1, posts1} = this.props;
return (
<div>
{posts1.items1 &&
<ul>
{posts1.items1.map((post1, index1) =>
<li key={post1.id}>
{post1.content} ({post1.id})
<input type="button" value="Send Data Working" onClick={() => this.handlePostId(post1.id, 55)} />
</li>
)}
</ul>
}
</div>
);
}
}
function mapStateToProps(state) {
const { posts1, post1} = state;
return {
post1,
posts1,
};
}
const connectedApp = connect(mapStateToProps)(App);
export { connectedApp as App }
Sample B Code
Here is my requirements and my issue with Sample Code B.
I have a requirements to create a Props and have records returns in it as per code below
const RenderPost = (props) => {
return (<React.Fragment><li >
{props.post1.id} - {props.post1.content}
<input type="button" value="Send Data not Working" onClick={() => props.handlePostId(props.post1.id, 55)} />
</li>
</React.Fragment>
);
};
In the Map function, I rendered Post records as follows
<RenderPost post1={post1} key={i} handlePostId={this.handlePostId} />
Sample B partly works as it displays record very well but my issue is that If I click on Send Data button so as to
post records to server backend, it will display error
Cannot read property 'dispatch' of undefined
at Object.handlePostId (bundle.js:73753)
at onClick.
Is props conflicting or what?.
Here is sample B code
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { Actions } from '../_actions';
const RenderPost = (props) => {
return (<React.Fragment><li >
{props.post1.id} - {props.post1.content}
<input type="button" value="Send Data not Working" onClick={() => props.handlePostId(props.post1.id, 55)} />
</li>
</React.Fragment>
);
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
this.props.dispatch(Actions.getRec());
}
handlePostId(postid,post_content) {
//return (e) => this.props.dispatch(Actions.sendData(postid,post_content));
return this.props.dispatch(Actions.sendData(postid,post_content));
}
render() {
const { post1, posts1} = this.props;
return (
<div>
{posts1.items1 &&
<ul>
{posts1.items1.map((post1, i) =>
<RenderPost post1={post1} key={i} handlePostId={this.handlePostId} />
)}
</ul>
}
</div>
);
}
}
function mapStateToProps(state) {
const { posts1, post1} = state;
return {
post1,
posts1,
};
}
const connectedApp = connect(mapStateToProps)(App);
export { connectedApp as App };
You have to bind the handlePostId function to the component
<RenderPost post1={post1} key={i} handlePostId={this.handlePostId.bind(this)} />
Looks like you didn't bind handlePostId in your constructor.
Alternatively, you could do this without needing to bind.
handlePostId = (postId, postContent) => {
return this.props.dispatch(Actions.sendData(postId, postContent));
}
Then call it like you did before:
<RenderPost post1={post1} key={i} handlePostId={this.handlePostId} />